GCC Code Coverage Report
Directory: . Exec Total Coverage
File: mjs.c Lines: 1535 5112 30.0 %
Date: 2018-11-15 19:58:04 Branches: 826 3901 21.2 %

Line Branch Exec Source
1
#include "mjs.h"
2
#ifdef MJS_MODULE_LINES
3
#line 1 "common/platform.h"
4
#endif
5
#ifndef CS_COMMON_PLATFORM_H_
6
#define CS_COMMON_PLATFORM_H_
7
8
/*
9
 * For the "custom" platform, includes and dependencies can be
10
 * provided through mg_locals.h.
11
 */
12
#define CS_P_CUSTOM 0
13
#define CS_P_UNIX 1
14
#define CS_P_WINDOWS 2
15
#define CS_P_ESP32 15
16
#define CS_P_ESP8266 3
17
#define CS_P_CC3100 6
18
#define CS_P_CC3200 4
19
#define CS_P_CC3220 17
20
#define CS_P_MSP432 5
21
#define CS_P_TM4C129 14
22
#define CS_P_MBED 7
23
#define CS_P_WINCE 8
24
#define CS_P_NXP_LPC 13
25
#define CS_P_NXP_KINETIS 9
26
#define CS_P_NRF51 12
27
#define CS_P_NRF52 10
28
#define CS_P_PIC32 11
29
#define CS_P_STM32 16
30
/* Next id: 18 */
31
32
/* If not specified explicitly, we guess platform by defines. */
33
#ifndef CS_PLATFORM
34
35
#if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__)
36
#define CS_PLATFORM CS_P_MSP432
37
#elif defined(cc3200) || defined(TARGET_IS_CC3200)
38
#define CS_PLATFORM CS_P_CC3200
39
#elif defined(cc3220) || defined(TARGET_IS_CC3220)
40
#define CS_PLATFORM CS_P_CC3220
41
#elif defined(__unix__) || defined(__APPLE__)
42
#define CS_PLATFORM CS_P_UNIX
43
#elif defined(WINCE)
44
#define CS_PLATFORM CS_P_WINCE
45
#elif defined(_WIN32)
46
#define CS_PLATFORM CS_P_WINDOWS
47
#elif defined(__MBED__)
48
#define CS_PLATFORM CS_P_MBED
49
#elif defined(__USE_LPCOPEN)
50
#define CS_PLATFORM CS_P_NXP_LPC
51
#elif defined(FRDM_K64F) || defined(FREEDOM)
52
#define CS_PLATFORM CS_P_NXP_KINETIS
53
#elif defined(PIC32)
54
#define CS_PLATFORM CS_P_PIC32
55
#elif defined(ESP_PLATFORM)
56
#define CS_PLATFORM CS_P_ESP32
57
#elif defined(ICACHE_FLASH)
58
#define CS_PLATFORM CS_P_ESP8266
59
#elif defined(TARGET_IS_TM4C129_RA0) || defined(TARGET_IS_TM4C129_RA1) || \
60
    defined(TARGET_IS_TM4C129_RA2)
61
#define CS_PLATFORM CS_P_TM4C129
62
#elif defined(STM32)
63
#define CS_PLATFORM CS_P_STM32
64
#endif
65
66
#ifndef CS_PLATFORM
67
#error "CS_PLATFORM is not specified and we couldn't guess it."
68
#endif
69
70
#endif /* !defined(CS_PLATFORM) */
71
72
#define MG_NET_IF_SOCKET 1
73
#define MG_NET_IF_SIMPLELINK 2
74
#define MG_NET_IF_LWIP_LOW_LEVEL 3
75
#define MG_NET_IF_PIC32 4
76
77
#define MG_SSL_IF_OPENSSL 1
78
#define MG_SSL_IF_MBEDTLS 2
79
#define MG_SSL_IF_SIMPLELINK 3
80
81
/* Amalgamated: #include "common/platforms/platform_unix.h" */
82
/* Amalgamated: #include "common/platforms/platform_windows.h" */
83
/* Amalgamated: #include "common/platforms/platform_esp32.h" */
84
/* Amalgamated: #include "common/platforms/platform_esp8266.h" */
85
/* Amalgamated: #include "common/platforms/platform_cc3100.h" */
86
/* Amalgamated: #include "common/platforms/platform_cc3200.h" */
87
/* Amalgamated: #include "common/platforms/platform_cc3220.h" */
88
/* Amalgamated: #include "common/platforms/platform_mbed.h" */
89
/* Amalgamated: #include "common/platforms/platform_nrf51.h" */
90
/* Amalgamated: #include "common/platforms/platform_nrf52.h" */
91
/* Amalgamated: #include "common/platforms/platform_wince.h" */
92
/* Amalgamated: #include "common/platforms/platform_nxp_lpc.h" */
93
/* Amalgamated: #include "common/platforms/platform_nxp_kinetis.h" */
94
/* Amalgamated: #include "common/platforms/platform_pic32.h" */
95
/* Amalgamated: #include "common/platforms/platform_stm32.h" */
96
97
/* Common stuff */
98
99
#if !defined(PRINTF_LIKE)
100
#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
101
#define PRINTF_LIKE(f, a) __attribute__((format(printf, f, a)))
102
#else
103
#define PRINTF_LIKE(f, a)
104
#endif
105
#endif
106
107
#if !defined(WEAK)
108
#if (defined(__GNUC__) || defined(__clang__) || \
109
     defined(__TI_COMPILER_VERSION__)) &&       \
110
    !defined(_WIN32)
111
#define WEAK __attribute__((weak))
112
#else
113
#define WEAK
114
#endif
115
#endif
116
117
#ifdef __GNUC__
118
#define NORETURN __attribute__((noreturn))
119
#define NOINLINE __attribute__((noinline))
120
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
121
#define NOINSTR __attribute__((no_instrument_function))
122
#define DO_NOT_WARN_UNUSED __attribute__((unused))
123
#else
124
#define NORETURN
125
#define NOINLINE
126
#define WARN_UNUSED_RESULT
127
#define NOINSTR
128
#define DO_NOT_WARN_UNUSED
129
#endif /* __GNUC__ */
130
131
#ifndef ARRAY_SIZE
132
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
133
#endif
134
135
#endif /* CS_COMMON_PLATFORM_H_ */
136
#ifdef MJS_MODULE_LINES
137
#line 1 "common/platforms/platform_windows.h"
138
#endif
139
#ifndef CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_
140
#define CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_
141
#if CS_PLATFORM == CS_P_WINDOWS
142
143
/*
144
 * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
145
 * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
146
 * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
147
 * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
148
 * MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)
149
 * MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)
150
 * MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio 2003)
151
 * MSVC++ 7.0  _MSC_VER == 1300
152
 * MSVC++ 6.0  _MSC_VER == 1200
153
 * MSVC++ 5.0  _MSC_VER == 1100
154
 */
155
#ifdef _MSC_VER
156
#pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */
157
#pragma warning(disable : 4204) /* missing c99 support */
158
#endif
159
160
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
161
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
162
#endif
163
164
#ifndef _CRT_SECURE_NO_WARNINGS
165
#define _CRT_SECURE_NO_WARNINGS
166
#endif
167
168
#include <assert.h>
169
#include <direct.h>
170
#include <errno.h>
171
#include <fcntl.h>
172
#include <io.h>
173
#include <limits.h>
174
#include <signal.h>
175
#include <stddef.h>
176
#include <stdio.h>
177
#include <stdlib.h>
178
#include <sys/stat.h>
179
#include <time.h>
180
#include <ctype.h>
181
182
#ifdef _MSC_VER
183
#pragma comment(lib, "ws2_32.lib") /* Linking with winsock library */
184
#endif
185
186
#include <winsock2.h>
187
#include <ws2tcpip.h>
188
#include <windows.h>
189
#include <process.h>
190
191
#if _MSC_VER < 1700
192
typedef int bool;
193
#else
194
#include <stdbool.h>
195
#endif
196
197
#if defined(_MSC_VER) && _MSC_VER >= 1800
198
#define strdup _strdup
199
#endif
200
201
#ifndef EINPROGRESS
202
#define EINPROGRESS WSAEINPROGRESS
203
#endif
204
#ifndef EWOULDBLOCK
205
#define EWOULDBLOCK WSAEWOULDBLOCK
206
#endif
207
#ifndef __func__
208
#define STRX(x) #x
209
#define STR(x) STRX(x)
210
#define __func__ __FILE__ ":" STR(__LINE__)
211
#endif
212
#define snprintf _snprintf
213
#define vsnprintf _vsnprintf
214
#define to64(x) _atoi64(x)
215
#if !defined(__MINGW32__) && !defined(__MINGW64__)
216
#define popen(x, y) _popen((x), (y))
217
#define pclose(x) _pclose(x)
218
#define fileno _fileno
219
#endif
220
#if defined(_MSC_VER) && _MSC_VER >= 1400
221
#define fseeko(x, y, z) _fseeki64((x), (y), (z))
222
#else
223
#define fseeko(x, y, z) fseek((x), (y), (z))
224
#endif
225
#if defined(_MSC_VER) && _MSC_VER <= 1200
226
typedef unsigned long uintptr_t;
227
typedef long intptr_t;
228
#endif
229
typedef int socklen_t;
230
#if _MSC_VER >= 1700
231
#include <stdint.h>
232
#else
233
typedef signed char int8_t;
234
typedef unsigned char uint8_t;
235
typedef int int32_t;
236
typedef unsigned int uint32_t;
237
typedef short int16_t;
238
typedef unsigned short uint16_t;
239
typedef __int64 int64_t;
240
typedef unsigned __int64 uint64_t;
241
#endif
242
typedef SOCKET sock_t;
243
typedef uint32_t in_addr_t;
244
#ifndef UINT16_MAX
245
#define UINT16_MAX 65535
246
#endif
247
#ifndef UINT32_MAX
248
#define UINT32_MAX 4294967295
249
#endif
250
#ifndef pid_t
251
#define pid_t HANDLE
252
#endif
253
#define INT64_FMT "I64d"
254
#define INT64_X_FMT "I64x"
255
#define SIZE_T_FMT "Iu"
256
typedef struct _stati64 cs_stat_t;
257
#ifndef S_ISDIR
258
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
259
#endif
260
#ifndef S_ISREG
261
#define S_ISREG(x) (((x) &_S_IFMT) == _S_IFREG)
262
#endif
263
#define DIRSEP '\\'
264
#define CS_DEFINE_DIRENT
265
266
#ifndef va_copy
267
#ifdef __va_copy
268
#define va_copy __va_copy
269
#else
270
#define va_copy(x, y) (x) = (y)
271
#endif
272
#endif
273
274
#ifndef MG_MAX_HTTP_REQUEST_SIZE
275
#define MG_MAX_HTTP_REQUEST_SIZE 8192
276
#endif
277
278
#ifndef MG_MAX_HTTP_SEND_MBUF
279
#define MG_MAX_HTTP_SEND_MBUF 4096
280
#endif
281
282
#ifndef MG_MAX_HTTP_HEADERS
283
#define MG_MAX_HTTP_HEADERS 40
284
#endif
285
286
#ifndef CS_ENABLE_STDIO
287
#define CS_ENABLE_STDIO 1
288
#endif
289
290
#ifndef MG_ENABLE_BROADCAST
291
#define MG_ENABLE_BROADCAST 1
292
#endif
293
294
#ifndef MG_ENABLE_DIRECTORY_LISTING
295
#define MG_ENABLE_DIRECTORY_LISTING 1
296
#endif
297
298
#ifndef MG_ENABLE_FILESYSTEM
299
#define MG_ENABLE_FILESYSTEM 1
300
#endif
301
302
#ifndef MG_ENABLE_HTTP_CGI
303
#define MG_ENABLE_HTTP_CGI MG_ENABLE_FILESYSTEM
304
#endif
305
306
#ifndef MG_NET_IF
307
#define MG_NET_IF MG_NET_IF_SOCKET
308
#endif
309
310
unsigned int sleep(unsigned int seconds);
311
312
/* https://stackoverflow.com/questions/16647819/timegm-cross-platform */
313
#define timegm _mkgmtime
314
315
#define gmtime_r(a, b) \
316
  do {                 \
317
    *(b) = *gmtime(a); \
318
  } while (0)
319
320
#endif /* CS_PLATFORM == CS_P_WINDOWS */
321
#endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */
322
#ifdef MJS_MODULE_LINES
323
#line 1 "common/platforms/platform_unix.h"
324
#endif
325
#ifndef CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_
326
#define CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_
327
#if CS_PLATFORM == CS_P_UNIX
328
329
#ifndef _XOPEN_SOURCE
330
#define _XOPEN_SOURCE 600
331
#endif
332
333
/* <inttypes.h> wants this for C++ */
334
#ifndef __STDC_FORMAT_MACROS
335
#define __STDC_FORMAT_MACROS
336
#endif
337
338
/* C++ wants that for INT64_MAX */
339
#ifndef __STDC_LIMIT_MACROS
340
#define __STDC_LIMIT_MACROS
341
#endif
342
343
/* Enable fseeko() and ftello() functions */
344
#ifndef _LARGEFILE_SOURCE
345
#define _LARGEFILE_SOURCE
346
#endif
347
348
/* Enable 64-bit file offsets */
349
#ifndef _FILE_OFFSET_BITS
350
#define _FILE_OFFSET_BITS 64
351
#endif
352
353
#include <arpa/inet.h>
354
#include <assert.h>
355
#include <ctype.h>
356
#include <dirent.h>
357
#include <errno.h>
358
#include <fcntl.h>
359
#include <inttypes.h>
360
#include <stdint.h>
361
#include <limits.h>
362
#include <math.h>
363
#include <netdb.h>
364
#include <netinet/in.h>
365
#include <pthread.h>
366
#include <signal.h>
367
#include <stdarg.h>
368
#include <stdbool.h>
369
#include <stdio.h>
370
#include <stdlib.h>
371
#include <string.h>
372
#include <sys/param.h>
373
#include <sys/socket.h>
374
#include <sys/select.h>
375
#include <sys/stat.h>
376
#include <sys/time.h>
377
#include <sys/types.h>
378
#include <unistd.h>
379
380
#ifdef __APPLE__
381
#include <machine/endian.h>
382
#ifndef BYTE_ORDER
383
#define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
384
#define BIG_ENDIAN __DARWIN_BIG_ENDIAN
385
#define PDP_ENDIAN __DARWIN_PDP_ENDIAN
386
#define BYTE_ORDER __DARWIN_BYTE_ORDER
387
#endif
388
#endif
389
390
/*
391
 * osx correctly avoids defining strtoll when compiling in strict ansi mode.
392
 * c++ 11 standard defines strtoll as well.
393
 * We require strtoll, and if your embedded pre-c99 compiler lacks one, please
394
 * implement a shim.
395
 */
396
#if !(defined(__cplusplus) && __cplusplus >= 201103L) && \
397
    !(defined(__DARWIN_C_LEVEL) && __DARWIN_C_LEVEL >= 200809L)
398
long long strtoll(const char *, char **, int);
399
#endif
400
401
typedef int sock_t;
402
#define INVALID_SOCKET (-1)
403
#define SIZE_T_FMT "zu"
404
typedef struct stat cs_stat_t;
405
#define DIRSEP '/'
406
#define to64(x) strtoll(x, NULL, 10)
407
#define INT64_FMT PRId64
408
#define INT64_X_FMT PRIx64
409
410
#ifndef __cdecl
411
#define __cdecl
412
#endif
413
414
#ifndef va_copy
415
#ifdef __va_copy
416
#define va_copy __va_copy
417
#else
418
#define va_copy(x, y) (x) = (y)
419
#endif
420
#endif
421
422
#define closesocket(x) close(x)
423
424
#ifndef MG_MAX_HTTP_REQUEST_SIZE
425
#define MG_MAX_HTTP_REQUEST_SIZE 8192
426
#endif
427
428
#ifndef MG_MAX_HTTP_SEND_MBUF
429
#define MG_MAX_HTTP_SEND_MBUF 4096
430
#endif
431
432
#ifndef MG_MAX_HTTP_HEADERS
433
#define MG_MAX_HTTP_HEADERS 40
434
#endif
435
436
#ifndef CS_ENABLE_STDIO
437
#define CS_ENABLE_STDIO 1
438
#endif
439
440
#ifndef MG_ENABLE_BROADCAST
441
#define MG_ENABLE_BROADCAST 1
442
#endif
443
444
#ifndef MG_ENABLE_DIRECTORY_LISTING
445
#define MG_ENABLE_DIRECTORY_LISTING 1
446
#endif
447
448
#ifndef MG_ENABLE_FILESYSTEM
449
#define MG_ENABLE_FILESYSTEM 1
450
#endif
451
452
#ifndef MG_ENABLE_HTTP_CGI
453
#define MG_ENABLE_HTTP_CGI MG_ENABLE_FILESYSTEM
454
#endif
455
456
#ifndef MG_NET_IF
457
#define MG_NET_IF MG_NET_IF_SOCKET
458
#endif
459
460
#ifndef MG_HOSTS_FILE_NAME
461
#define MG_HOSTS_FILE_NAME "/etc/hosts"
462
#endif
463
464
#ifndef MG_RESOLV_CONF_FILE_NAME
465
#define MG_RESOLV_CONF_FILE_NAME "/etc/resolv.conf"
466
#endif
467
468
#endif /* CS_PLATFORM == CS_P_UNIX */
469
#endif /* CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ */
470
#ifdef MJS_MODULE_LINES
471
#line 1 "common/platforms/platform_esp32.h"
472
#endif
473
/*
474
 * Copyright (c) 2014-2018 Cesanta Software Limited
475
 * All rights reserved
476
 *
477
 * Licensed under the Apache License, Version 2.0 (the ""License"");
478
 * you may not use this file except in compliance with the License.
479
 * You may obtain a copy of the License at
480
 *
481
 *     http://www.apache.org/licenses/LICENSE-2.0
482
 *
483
 * Unless required by applicable law or agreed to in writing, software
484
 * distributed under the License is distributed on an ""AS IS"" BASIS,
485
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
486
 * See the License for the specific language governing permissions and
487
 * limitations under the License.
488
 */
489
490
#ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_
491
#define CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_
492
#if CS_PLATFORM == CS_P_ESP32
493
494
#include <assert.h>
495
#include <ctype.h>
496
#include <dirent.h>
497
#include <fcntl.h>
498
#include <inttypes.h>
499
#include <machine/endian.h>
500
#include <stdbool.h>
501
#include <stdint.h>
502
#include <string.h>
503
#include <sys/stat.h>
504
#include <sys/time.h>
505
506
#define SIZE_T_FMT "u"
507
typedef struct stat cs_stat_t;
508
#define DIRSEP '/'
509
#define to64(x) strtoll(x, NULL, 10)
510
#define INT64_FMT PRId64
511
#define INT64_X_FMT PRIx64
512
#define __cdecl
513
#define _FILE_OFFSET_BITS 32
514
515
#define MG_LWIP 1
516
517
#ifndef MG_NET_IF
518
#define MG_NET_IF MG_NET_IF_SOCKET
519
#endif
520
521
#ifndef CS_ENABLE_STDIO
522
#define CS_ENABLE_STDIO 1
523
#endif
524
525
#endif /* CS_PLATFORM == CS_P_ESP32 */
526
#endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP32_H_ */
527
#ifdef MJS_MODULE_LINES
528
#line 1 "common/platforms/platform_esp8266.h"
529
#endif
530
/*
531
 * Copyright (c) 2014-2018 Cesanta Software Limited
532
 * All rights reserved
533
 *
534
 * Licensed under the Apache License, Version 2.0 (the ""License"");
535
 * you may not use this file except in compliance with the License.
536
 * You may obtain a copy of the License at
537
 *
538
 *     http://www.apache.org/licenses/LICENSE-2.0
539
 *
540
 * Unless required by applicable law or agreed to in writing, software
541
 * distributed under the License is distributed on an ""AS IS"" BASIS,
542
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
543
 * See the License for the specific language governing permissions and
544
 * limitations under the License.
545
 */
546
547
#ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_
548
#define CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_
549
#if CS_PLATFORM == CS_P_ESP8266
550
551
#include <assert.h>
552
#include <ctype.h>
553
#include <fcntl.h>
554
#include <inttypes.h>
555
#include <machine/endian.h>
556
#include <stdbool.h>
557
#include <string.h>
558
#include <sys/stat.h>
559
#include <sys/time.h>
560
561
#define SIZE_T_FMT "u"
562
typedef struct stat cs_stat_t;
563
#define DIRSEP '/'
564
#if !defined(MGOS_VFS_DEFINE_DIRENT)
565
#define CS_DEFINE_DIRENT
566
#endif
567
568
#define to64(x) strtoll(x, NULL, 10)
569
#define INT64_FMT PRId64
570
#define INT64_X_FMT PRIx64
571
#define __cdecl
572
#define _FILE_OFFSET_BITS 32
573
574
#define MG_LWIP 1
575
576
/* struct timeval is defined in sys/time.h. */
577
#define LWIP_TIMEVAL_PRIVATE 0
578
579
#ifndef MG_NET_IF
580
#include <lwip/opt.h>
581
#if LWIP_SOCKET /* RTOS SDK has LWIP sockets */
582
#define MG_NET_IF MG_NET_IF_SOCKET
583
#else
584
#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
585
#endif
586
#endif
587
588
#ifndef CS_ENABLE_STDIO
589
#define CS_ENABLE_STDIO 1
590
#endif
591
592
#define inet_ntop(af, src, dst, size)                                          \
593
  (((af) == AF_INET) ? ipaddr_ntoa_r((const ip_addr_t *) (src), (dst), (size)) \
594
                     : NULL)
595
#define inet_pton(af, src, dst) \
596
  (((af) == AF_INET) ? ipaddr_aton((src), (ip_addr_t *) (dst)) : 0)
597
598
#endif /* CS_PLATFORM == CS_P_ESP8266 */
599
#endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP8266_H_ */
600
#ifdef MJS_MODULE_LINES
601
#line 1 "common/platforms/platform_cc3100.h"
602
#endif
603
/*
604
 * Copyright (c) 2014-2018 Cesanta Software Limited
605
 * All rights reserved
606
 *
607
 * Licensed under the Apache License, Version 2.0 (the ""License"");
608
 * you may not use this file except in compliance with the License.
609
 * You may obtain a copy of the License at
610
 *
611
 *     http://www.apache.org/licenses/LICENSE-2.0
612
 *
613
 * Unless required by applicable law or agreed to in writing, software
614
 * distributed under the License is distributed on an ""AS IS"" BASIS,
615
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
616
 * See the License for the specific language governing permissions and
617
 * limitations under the License.
618
 */
619
620
#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_
621
#define CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_
622
#if CS_PLATFORM == CS_P_CC3100
623
624
#include <assert.h>
625
#include <ctype.h>
626
#include <errno.h>
627
#include <inttypes.h>
628
#include <stdint.h>
629
#include <string.h>
630
#include <time.h>
631
632
#define MG_NET_IF MG_NET_IF_SIMPLELINK
633
#define MG_SSL_IF MG_SSL_IF_SIMPLELINK
634
635
/*
636
 * CC3100 SDK and STM32 SDK include headers w/out path, just like
637
 * #include "simplelink.h". As result, we have to add all required directories
638
 * into Makefile IPATH and do the same thing (include w/out path)
639
 */
640
641
#include <simplelink.h>
642
#include <netapp.h>
643
#undef timeval
644
645
typedef int sock_t;
646
#define INVALID_SOCKET (-1)
647
648
#define to64(x) strtoll(x, NULL, 10)
649
#define INT64_FMT PRId64
650
#define INT64_X_FMT PRIx64
651
#define SIZE_T_FMT "u"
652
653
#define SOMAXCONN 8
654
655
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
656
char *inet_ntoa(struct in_addr in);
657
int inet_pton(int af, const char *src, void *dst);
658
659
#endif /* CS_PLATFORM == CS_P_CC3100 */
660
#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ */
661
#ifdef MJS_MODULE_LINES
662
#line 1 "common/platforms/simplelink/cs_simplelink.h"
663
#endif
664
/*
665
 * Copyright (c) 2014-2018 Cesanta Software Limited
666
 * All rights reserved
667
 *
668
 * Licensed under the Apache License, Version 2.0 (the ""License"");
669
 * you may not use this file except in compliance with the License.
670
 * You may obtain a copy of the License at
671
 *
672
 *     http://www.apache.org/licenses/LICENSE-2.0
673
 *
674
 * Unless required by applicable law or agreed to in writing, software
675
 * distributed under the License is distributed on an ""AS IS"" BASIS,
676
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
677
 * See the License for the specific language governing permissions and
678
 * limitations under the License.
679
 */
680
681
#ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_
682
#define CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_
683
684
#if defined(MG_NET_IF) && MG_NET_IF == MG_NET_IF_SIMPLELINK
685
686
/* If simplelink.h is already included, all bets are off. */
687
#if !defined(__SIMPLELINK_H__)
688
689
#include <stdbool.h>
690
691
#ifndef __TI_COMPILER_VERSION__
692
#undef __CONCAT
693
#undef FD_CLR
694
#undef FD_ISSET
695
#undef FD_SET
696
#undef FD_SETSIZE
697
#undef FD_ZERO
698
#undef fd_set
699
#endif
700
701
#if CS_PLATFORM == CS_P_CC3220
702
#include <ti/drivers/net/wifi/porting/user.h>
703
#include <ti/drivers/net/wifi/simplelink.h>
704
#include <ti/drivers/net/wifi/sl_socket.h>
705
#include <ti/drivers/net/wifi/netapp.h>
706
#else
707
/* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves
708
 * and undef it. */
709
#define PROVISIONING_API_H_
710
#include <simplelink/user.h>
711
#undef PROVISIONING_API_H_
712
#undef SL_INC_STD_BSD_API_NAMING
713
714
#include <simplelink/include/simplelink.h>
715
#include <simplelink/include/netapp.h>
716
#endif /* CS_PLATFORM == CS_P_CC3220 */
717
718
/* Now define only the subset of the BSD API that we use.
719
 * Notably, close(), read() and write() are not defined. */
720
#define AF_INET SL_AF_INET
721
722
#define socklen_t SlSocklen_t
723
#define sockaddr SlSockAddr_t
724
#define sockaddr_in SlSockAddrIn_t
725
#define in_addr SlInAddr_t
726
727
#define SOCK_STREAM SL_SOCK_STREAM
728
#define SOCK_DGRAM SL_SOCK_DGRAM
729
730
#define htonl sl_Htonl
731
#define ntohl sl_Ntohl
732
#define htons sl_Htons
733
#define ntohs sl_Ntohs
734
735
#ifndef EACCES
736
#define EACCES SL_EACCES
737
#endif
738
#ifndef EAFNOSUPPORT
739
#define EAFNOSUPPORT SL_EAFNOSUPPORT
740
#endif
741
#ifndef EAGAIN
742
#define EAGAIN SL_EAGAIN
743
#endif
744
#ifndef EBADF
745
#define EBADF SL_EBADF
746
#endif
747
#ifndef EINVAL
748
#define EINVAL SL_EINVAL
749
#endif
750
#ifndef ENOMEM
751
#define ENOMEM SL_ENOMEM
752
#endif
753
#ifndef EWOULDBLOCK
754
#define EWOULDBLOCK SL_EWOULDBLOCK
755
#endif
756
757
#define SOMAXCONN 8
758
759
#ifdef __cplusplus
760
extern "C" {
761
#endif
762
763
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
764
char *inet_ntoa(struct in_addr in);
765
int inet_pton(int af, const char *src, void *dst);
766
767
struct mg_mgr;
768
struct mg_connection;
769
770
typedef void (*mg_init_cb)(struct mg_mgr *mgr);
771
bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init);
772
773
void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg);
774
775
int sl_fs_init(void);
776
777
void sl_restart_cb(struct mg_mgr *mgr);
778
779
int sl_set_ssl_opts(int sock, struct mg_connection *nc);
780
781
#ifdef __cplusplus
782
}
783
#endif
784
785
#endif /* !defined(__SIMPLELINK_H__) */
786
787
/* Compatibility with older versions of SimpleLink */
788
#if SL_MAJOR_VERSION_NUM < 2
789
790
#define SL_ERROR_BSD_EAGAIN SL_EAGAIN
791
#define SL_ERROR_BSD_EALREADY SL_EALREADY
792
#define SL_ERROR_BSD_ENOPROTOOPT SL_ENOPROTOOPT
793
#define SL_ERROR_BSD_ESECDATEERROR SL_ESECDATEERROR
794
#define SL_ERROR_BSD_ESECSNOVERIFY SL_ESECSNOVERIFY
795
#define SL_ERROR_FS_FAILED_TO_ALLOCATE_MEM SL_FS_ERR_FAILED_TO_ALLOCATE_MEM
796
#define SL_ERROR_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY \
797
  SL_FS_FILE_HAS_NOT_BEEN_CLOSE_CORRECTLY
798
#define SL_ERROR_FS_FILE_NAME_EXIST SL_FS_FILE_NAME_EXIST
799
#define SL_ERROR_FS_FILE_NOT_EXISTS SL_FS_ERR_FILE_NOT_EXISTS
800
#define SL_ERROR_FS_NO_AVAILABLE_NV_INDEX SL_FS_ERR_NO_AVAILABLE_NV_INDEX
801
#define SL_ERROR_FS_NOT_ENOUGH_STORAGE_SPACE SL_FS_ERR_NO_AVAILABLE_BLOCKS
802
#define SL_ERROR_FS_NOT_SUPPORTED SL_FS_ERR_NOT_SUPPORTED
803
#define SL_ERROR_FS_WRONG_FILE_NAME SL_FS_WRONG_FILE_NAME
804
#define SL_ERROR_FS_INVALID_HANDLE SL_FS_ERR_INVALID_HANDLE
805
#define SL_NETCFG_MAC_ADDRESS_GET SL_MAC_ADDRESS_GET
806
#define SL_SOCKET_FD_ZERO SL_FD_ZERO
807
#define SL_SOCKET_FD_SET SL_FD_SET
808
#define SL_SOCKET_FD_ISSET SL_FD_ISSET
809
#define SL_SO_SECURE_DOMAIN_NAME_VERIFICATION SO_SECURE_DOMAIN_NAME_VERIFICATION
810
811
#define SL_FS_READ FS_MODE_OPEN_READ
812
#define SL_FS_WRITE FS_MODE_OPEN_WRITE
813
814
#define SL_FI_FILE_SIZE(fi) ((fi).FileLen)
815
#define SL_FI_FILE_MAX_SIZE(fi) ((fi).AllocatedLen)
816
817
#define SlDeviceVersion_t SlVersionFull
818
#define sl_DeviceGet sl_DevGet
819
#define SL_DEVICE_GENERAL SL_DEVICE_GENERAL_CONFIGURATION
820
#define SL_LEN_TYPE _u8
821
#define SL_OPT_TYPE _u8
822
823
#else /* SL_MAJOR_VERSION_NUM >= 2 */
824
825
#define FS_MODE_OPEN_CREATE(max_size, flag) \
826
  (SL_FS_CREATE | SL_FS_CREATE_MAX_SIZE(max_size))
827
#define SL_FI_FILE_SIZE(fi) ((fi).Len)
828
#define SL_FI_FILE_MAX_SIZE(fi) ((fi).MaxSize)
829
830
#define SL_LEN_TYPE _u16
831
#define SL_OPT_TYPE _u16
832
833
#endif /* SL_MAJOR_VERSION_NUM < 2 */
834
835
int slfs_open(const unsigned char *fname, uint32_t flags);
836
837
#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
838
839
#endif /* CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ */
840
#ifdef MJS_MODULE_LINES
841
#line 1 "common/platforms/platform_cc3200.h"
842
#endif
843
/*
844
 * Copyright (c) 2014-2018 Cesanta Software Limited
845
 * All rights reserved
846
 *
847
 * Licensed under the Apache License, Version 2.0 (the ""License"");
848
 * you may not use this file except in compliance with the License.
849
 * You may obtain a copy of the License at
850
 *
851
 *     http://www.apache.org/licenses/LICENSE-2.0
852
 *
853
 * Unless required by applicable law or agreed to in writing, software
854
 * distributed under the License is distributed on an ""AS IS"" BASIS,
855
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
856
 * See the License for the specific language governing permissions and
857
 * limitations under the License.
858
 */
859
860
#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_
861
#define CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_
862
#if CS_PLATFORM == CS_P_CC3200
863
864
#include <assert.h>
865
#include <ctype.h>
866
#include <errno.h>
867
#include <inttypes.h>
868
#include <stdbool.h>
869
#include <stdint.h>
870
#include <string.h>
871
#include <time.h>
872
873
#ifndef __TI_COMPILER_VERSION__
874
#include <fcntl.h>
875
#include <sys/time.h>
876
#endif
877
878
#define MG_NET_IF MG_NET_IF_SIMPLELINK
879
#define MG_SSL_IF MG_SSL_IF_SIMPLELINK
880
881
/* Only SPIFFS supports directories, SLFS does not. */
882
#if defined(CC3200_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING)
883
#define MG_ENABLE_DIRECTORY_LISTING 1
884
#endif
885
886
/* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */
887
888
typedef int sock_t;
889
#define INVALID_SOCKET (-1)
890
#define SIZE_T_FMT "u"
891
typedef struct stat cs_stat_t;
892
#define DIRSEP '/'
893
#define to64(x) strtoll(x, NULL, 10)
894
#define INT64_FMT PRId64
895
#define INT64_X_FMT PRIx64
896
#define __cdecl
897
898
#define fileno(x) -1
899
900
/* Some functions we implement for Mongoose. */
901
902
#ifdef __cplusplus
903
extern "C" {
904
#endif
905
906
#ifdef __TI_COMPILER_VERSION__
907
struct SlTimeval_t;
908
#define timeval SlTimeval_t
909
int gettimeofday(struct timeval *t, void *tz);
910
int settimeofday(const struct timeval *tv, const void *tz);
911
912
int asprintf(char **strp, const char *fmt, ...);
913
914
#endif
915
916
/* TI's libc does not have stat & friends, add them. */
917
#ifdef __TI_COMPILER_VERSION__
918
919
#include <file.h>
920
921
typedef unsigned int mode_t;
922
typedef size_t _off_t;
923
typedef long ssize_t;
924
925
struct stat {
926
  int st_ino;
927
  mode_t st_mode;
928
  int st_nlink;
929
  time_t st_mtime;
930
  off_t st_size;
931
};
932
933
int _stat(const char *pathname, struct stat *st);
934
int stat(const char *pathname, struct stat *st);
935
936
#define __S_IFMT 0170000
937
938
#define __S_IFDIR 0040000
939
#define __S_IFCHR 0020000
940
#define __S_IFREG 0100000
941
942
#define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask))
943
944
#define S_IFDIR __S_IFDIR
945
#define S_IFCHR __S_IFCHR
946
#define S_IFREG __S_IFREG
947
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
948
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
949
950
/* 5.x series compilers don't have va_copy, 16.x do. */
951
#if __TI_COMPILER_VERSION__ < 16000000
952
#define va_copy(apc, ap) ((apc) = (ap))
953
#endif
954
955
#endif /* __TI_COMPILER_VERSION__ */
956
957
#ifdef CC3200_FS_SLFS
958
#define MG_FS_SLFS
959
#endif
960
961
#if (defined(CC3200_FS_SPIFFS) || defined(CC3200_FS_SLFS)) && \
962
    !defined(MG_ENABLE_FILESYSTEM)
963
#define MG_ENABLE_FILESYSTEM 1
964
#define CS_DEFINE_DIRENT
965
#endif
966
967
#ifndef CS_ENABLE_STDIO
968
#define CS_ENABLE_STDIO 1
969
#endif
970
971
#ifdef __cplusplus
972
}
973
#endif
974
975
#endif /* CS_PLATFORM == CS_P_CC3200 */
976
#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */
977
#ifdef MJS_MODULE_LINES
978
#line 1 "common/platforms/platform_cc3220.h"
979
#endif
980
/*
981
 * Copyright (c) 2014-2018 Cesanta Software Limited
982
 * All rights reserved
983
 *
984
 * Licensed under the Apache License, Version 2.0 (the ""License"");
985
 * you may not use this file except in compliance with the License.
986
 * You may obtain a copy of the License at
987
 *
988
 *     http://www.apache.org/licenses/LICENSE-2.0
989
 *
990
 * Unless required by applicable law or agreed to in writing, software
991
 * distributed under the License is distributed on an ""AS IS"" BASIS,
992
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
993
 * See the License for the specific language governing permissions and
994
 * limitations under the License.
995
 */
996
997
#ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_
998
#define CS_COMMON_PLATFORMS_PLATFORM_CC3220_H_
999
#if CS_PLATFORM == CS_P_CC3220
1000
1001
#include <assert.h>
1002
#include <ctype.h>
1003
#include <errno.h>
1004
#include <inttypes.h>
1005
#include <stdbool.h>
1006
#include <stdint.h>
1007
#include <string.h>
1008
#include <time.h>
1009
1010
#ifndef __TI_COMPILER_VERSION__
1011
#include <fcntl.h>
1012
#include <sys/time.h>
1013
#endif
1014
1015
#define MG_NET_IF MG_NET_IF_SIMPLELINK
1016
#ifndef MG_SSL_IF
1017
#define MG_SSL_IF MG_SSL_IF_SIMPLELINK
1018
#endif
1019
1020
/* Only SPIFFS supports directories, SLFS does not. */
1021
#if defined(CC3220_FS_SPIFFS) && !defined(MG_ENABLE_DIRECTORY_LISTING)
1022
#define MG_ENABLE_DIRECTORY_LISTING 1
1023
#endif
1024
1025
/* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */
1026
1027
typedef int sock_t;
1028
#define INVALID_SOCKET (-1)
1029
#define SIZE_T_FMT "u"
1030
typedef struct stat cs_stat_t;
1031
#define DIRSEP '/'
1032
#define to64(x) strtoll(x, NULL, 10)
1033
#define INT64_FMT PRId64
1034
#define INT64_X_FMT PRIx64
1035
#define __cdecl
1036
1037
#define fileno(x) -1
1038
1039
/* Some functions we implement for Mongoose. */
1040
1041
#ifdef __cplusplus
1042
extern "C" {
1043
#endif
1044
1045
#ifdef __TI_COMPILER_VERSION__
1046
struct SlTimeval_t;
1047
#define timeval SlTimeval_t
1048
int gettimeofday(struct timeval *t, void *tz);
1049
int settimeofday(const struct timeval *tv, const void *tz);
1050
1051
int asprintf(char **strp, const char *fmt, ...);
1052
1053
#endif
1054
1055
/* TI's libc does not have stat & friends, add them. */
1056
#ifdef __TI_COMPILER_VERSION__
1057
1058
#include <file.h>
1059
1060
typedef unsigned int mode_t;
1061
typedef size_t _off_t;
1062
typedef long ssize_t;
1063
1064
struct stat {
1065
  int st_ino;
1066
  mode_t st_mode;
1067
  int st_nlink;
1068
  time_t st_mtime;
1069
  off_t st_size;
1070
};
1071
1072
int _stat(const char *pathname, struct stat *st);
1073
int stat(const char *pathname, struct stat *st);
1074
1075
#define __S_IFMT 0170000
1076
1077
#define __S_IFDIR 0040000
1078
#define __S_IFCHR 0020000
1079
#define __S_IFREG 0100000
1080
1081
#define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask))
1082
1083
#define S_IFDIR __S_IFDIR
1084
#define S_IFCHR __S_IFCHR
1085
#define S_IFREG __S_IFREG
1086
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
1087
#define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
1088
1089
#endif /* __TI_COMPILER_VERSION__ */
1090
1091
#ifndef CS_ENABLE_STDIO
1092
#define CS_ENABLE_STDIO 1
1093
#endif
1094
1095
#ifdef __cplusplus
1096
}
1097
#endif
1098
1099
#endif /* CS_PLATFORM == CS_P_CC3220 */
1100
#endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */
1101
#ifdef MJS_MODULE_LINES
1102
#line 1 "common/platforms/platform_mbed.h"
1103
#endif
1104
/*
1105
 * Copyright (c) 2014-2018 Cesanta Software Limited
1106
 * All rights reserved
1107
 *
1108
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1109
 * you may not use this file except in compliance with the License.
1110
 * You may obtain a copy of the License at
1111
 *
1112
 *     http://www.apache.org/licenses/LICENSE-2.0
1113
 *
1114
 * Unless required by applicable law or agreed to in writing, software
1115
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1116
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1117
 * See the License for the specific language governing permissions and
1118
 * limitations under the License.
1119
 */
1120
1121
#ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_
1122
#define CS_COMMON_PLATFORMS_PLATFORM_MBED_H_
1123
#if CS_PLATFORM == CS_P_MBED
1124
1125
/*
1126
 * mbed.h contains C++ code (e.g. templates), thus, it should be processed
1127
 * only if included directly to startup file (ex: main.cpp)
1128
 */
1129
#ifdef __cplusplus
1130
/* Amalgamated: #include "mbed.h" */
1131
#endif /* __cplusplus */
1132
1133
#include <assert.h>
1134
#include <ctype.h>
1135
#include <errno.h>
1136
#include <inttypes.h>
1137
#include <stdint.h>
1138
#include <string.h>
1139
#include <time.h>
1140
#include <sys/stat.h>
1141
#include <sys/types.h>
1142
#include <fcntl.h>
1143
#include <stdio.h>
1144
1145
typedef struct stat cs_stat_t;
1146
#define DIRSEP '/'
1147
1148
#ifndef CS_ENABLE_STDIO
1149
#define CS_ENABLE_STDIO 1
1150
#endif
1151
1152
/*
1153
 * mbed can be compiled with the ARM compiler which
1154
 * just doesn't come with a gettimeofday shim
1155
 * because it's a BSD API and ARM targets embedded
1156
 * non-unix platforms.
1157
 */
1158
#if defined(__ARMCC_VERSION) || defined(__ICCARM__)
1159
#define _TIMEVAL_DEFINED
1160
#define gettimeofday _gettimeofday
1161
1162
/* copied from GCC on ARM; for some reason useconds are signed */
1163
typedef long suseconds_t; /* microseconds (signed) */
1164
struct timeval {
1165
  time_t tv_sec;       /* seconds */
1166
  suseconds_t tv_usec; /* and microseconds */
1167
};
1168
1169
#endif
1170
1171
#if MG_NET_IF == MG_NET_IF_SIMPLELINK
1172
1173
#define MG_SIMPLELINK_NO_OSI 1
1174
1175
#include <simplelink.h>
1176
1177
typedef int sock_t;
1178
#define INVALID_SOCKET (-1)
1179
1180
#define to64(x) strtoll(x, NULL, 10)
1181
#define INT64_FMT PRId64
1182
#define INT64_X_FMT PRIx64
1183
#define SIZE_T_FMT "u"
1184
1185
#define SOMAXCONN 8
1186
1187
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
1188
char *inet_ntoa(struct in_addr in);
1189
int inet_pton(int af, const char *src, void *dst);
1190
int inet_aton(const char *cp, struct in_addr *inp);
1191
in_addr_t inet_addr(const char *cp);
1192
1193
#endif /* MG_NET_IF == MG_NET_IF_SIMPLELINK */
1194
1195
#endif /* CS_PLATFORM == CS_P_MBED */
1196
#endif /* CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ */
1197
#ifdef MJS_MODULE_LINES
1198
#line 1 "common/platforms/platform_nrf51.h"
1199
#endif
1200
/*
1201
 * Copyright (c) 2014-2018 Cesanta Software Limited
1202
 * All rights reserved
1203
 *
1204
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1205
 * you may not use this file except in compliance with the License.
1206
 * You may obtain a copy of the License at
1207
 *
1208
 *     http://www.apache.org/licenses/LICENSE-2.0
1209
 *
1210
 * Unless required by applicable law or agreed to in writing, software
1211
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1212
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1213
 * See the License for the specific language governing permissions and
1214
 * limitations under the License.
1215
 */
1216
#ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
1217
#define CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_
1218
#if CS_PLATFORM == CS_P_NRF51
1219
1220
#include <assert.h>
1221
#include <ctype.h>
1222
#include <inttypes.h>
1223
#include <stdint.h>
1224
#include <string.h>
1225
#include <time.h>
1226
1227
#define to64(x) strtoll(x, NULL, 10)
1228
1229
#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
1230
#define MG_LWIP 1
1231
#define MG_ENABLE_IPV6 1
1232
1233
/*
1234
 * For ARM C Compiler, make lwip to export `struct timeval`; for other
1235
 * compilers, suppress it.
1236
 */
1237
#if !defined(__ARMCC_VERSION)
1238
#define LWIP_TIMEVAL_PRIVATE 0
1239
#else
1240
struct timeval;
1241
int gettimeofday(struct timeval *tp, void *tzp);
1242
#endif
1243
1244
#define INT64_FMT PRId64
1245
#define SIZE_T_FMT "u"
1246
1247
/*
1248
 * ARM C Compiler doesn't have strdup, so we provide it
1249
 */
1250
#define CS_ENABLE_STRDUP defined(__ARMCC_VERSION)
1251
1252
#endif /* CS_PLATFORM == CS_P_NRF51 */
1253
#endif /* CS_COMMON_PLATFORMS_PLATFORM_NRF51_H_ */
1254
#ifdef MJS_MODULE_LINES
1255
#line 1 "common/platforms/platform_nrf52.h"
1256
#endif
1257
/*
1258
 * Copyright (c) 2014-2018 Cesanta Software Limited
1259
 * All rights reserved
1260
 *
1261
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1262
 * you may not use this file except in compliance with the License.
1263
 * You may obtain a copy of the License at
1264
 *
1265
 *     http://www.apache.org/licenses/LICENSE-2.0
1266
 *
1267
 * Unless required by applicable law or agreed to in writing, software
1268
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1269
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1270
 * See the License for the specific language governing permissions and
1271
 * limitations under the License.
1272
 */
1273
#ifndef CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
1274
#define CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_
1275
#if CS_PLATFORM == CS_P_NRF52
1276
1277
#include <assert.h>
1278
#include <ctype.h>
1279
#include <errno.h>
1280
#include <inttypes.h>
1281
#include <stdbool.h>
1282
#include <stdint.h>
1283
#include <string.h>
1284
#include <time.h>
1285
1286
#define to64(x) strtoll(x, NULL, 10)
1287
1288
#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
1289
#define MG_LWIP 1
1290
#define MG_ENABLE_IPV6 1
1291
1292
#if !defined(ENOSPC)
1293
#define ENOSPC 28 /* No space left on device */
1294
#endif
1295
1296
/*
1297
 * For ARM C Compiler, make lwip to export `struct timeval`; for other
1298
 * compilers, suppress it.
1299
 */
1300
#if !defined(__ARMCC_VERSION)
1301
#define LWIP_TIMEVAL_PRIVATE 0
1302
#endif
1303
1304
#define INT64_FMT PRId64
1305
#define SIZE_T_FMT "u"
1306
1307
/*
1308
 * ARM C Compiler doesn't have strdup, so we provide it
1309
 */
1310
#define CS_ENABLE_STRDUP defined(__ARMCC_VERSION)
1311
1312
#endif /* CS_PLATFORM == CS_P_NRF52 */
1313
#endif /* CS_COMMON_PLATFORMS_PLATFORM_NRF52_H_ */
1314
#ifdef MJS_MODULE_LINES
1315
#line 1 "common/platforms/platform_wince.h"
1316
#endif
1317
#ifndef CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_
1318
#define CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_
1319
1320
#if CS_PLATFORM == CS_P_WINCE
1321
1322
/*
1323
 * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
1324
 * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
1325
 * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
1326
 * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
1327
 * MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)
1328
 * MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)
1329
 * MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio 2003)
1330
 * MSVC++ 7.0  _MSC_VER == 1300
1331
 * MSVC++ 6.0  _MSC_VER == 1200
1332
 * MSVC++ 5.0  _MSC_VER == 1100
1333
 */
1334
#pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */
1335
#pragma warning(disable : 4204) /* missing c99 support */
1336
1337
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
1338
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
1339
#endif
1340
1341
#ifndef _CRT_SECURE_NO_WARNINGS
1342
#define _CRT_SECURE_NO_WARNINGS
1343
#endif
1344
1345
#include <assert.h>
1346
#include <limits.h>
1347
#include <stddef.h>
1348
#include <stdio.h>
1349
#include <stdlib.h>
1350
#include <time.h>
1351
1352
#pragma comment(lib, "ws2.lib") /* Linking with WinCE winsock library */
1353
1354
#include <winsock2.h>
1355
#include <ws2tcpip.h>
1356
#include <windows.h>
1357
1358
#define strdup _strdup
1359
1360
#ifndef EINPROGRESS
1361
#define EINPROGRESS WSAEINPROGRESS
1362
#endif
1363
1364
#ifndef EWOULDBLOCK
1365
#define EWOULDBLOCK WSAEWOULDBLOCK
1366
#endif
1367
1368
#ifndef EAGAIN
1369
#define EAGAIN EWOULDBLOCK
1370
#endif
1371
1372
#ifndef __func__
1373
#define STRX(x) #x
1374
#define STR(x) STRX(x)
1375
#define __func__ __FILE__ ":" STR(__LINE__)
1376
#endif
1377
1378
#define snprintf _snprintf
1379
#define fileno _fileno
1380
#define vsnprintf _vsnprintf
1381
#define sleep(x) Sleep((x) *1000)
1382
#define to64(x) _atoi64(x)
1383
#define rmdir _rmdir
1384
1385
#if defined(_MSC_VER) && _MSC_VER >= 1400
1386
#define fseeko(x, y, z) _fseeki64((x), (y), (z))
1387
#else
1388
#define fseeko(x, y, z) fseek((x), (y), (z))
1389
#endif
1390
1391
typedef int socklen_t;
1392
1393
#if _MSC_VER >= 1700
1394
#include <stdint.h>
1395
#else
1396
typedef signed char int8_t;
1397
typedef unsigned char uint8_t;
1398
typedef int int32_t;
1399
typedef unsigned int uint32_t;
1400
typedef short int16_t;
1401
typedef unsigned short uint16_t;
1402
typedef __int64 int64_t;
1403
typedef unsigned __int64 uint64_t;
1404
#endif
1405
1406
typedef SOCKET sock_t;
1407
typedef uint32_t in_addr_t;
1408
1409
#ifndef UINT16_MAX
1410
#define UINT16_MAX 65535
1411
#endif
1412
1413
#ifndef UINT32_MAX
1414
#define UINT32_MAX 4294967295
1415
#endif
1416
1417
#ifndef pid_t
1418
#define pid_t HANDLE
1419
#endif
1420
1421
#define INT64_FMT "I64d"
1422
#define INT64_X_FMT "I64x"
1423
/* TODO(alashkin): check if this is correct */
1424
#define SIZE_T_FMT "u"
1425
1426
#define DIRSEP '\\'
1427
#define CS_DEFINE_DIRENT
1428
1429
#ifndef va_copy
1430
#ifdef __va_copy
1431
#define va_copy __va_copy
1432
#else
1433
#define va_copy(x, y) (x) = (y)
1434
#endif
1435
#endif
1436
1437
#ifndef MG_MAX_HTTP_REQUEST_SIZE
1438
#define MG_MAX_HTTP_REQUEST_SIZE 8192
1439
#endif
1440
1441
#ifndef MG_MAX_HTTP_SEND_MBUF
1442
#define MG_MAX_HTTP_SEND_MBUF 4096
1443
#endif
1444
1445
#ifndef MG_MAX_HTTP_HEADERS
1446
#define MG_MAX_HTTP_HEADERS 40
1447
#endif
1448
1449
#ifndef CS_ENABLE_STDIO
1450
#define CS_ENABLE_STDIO 1
1451
#endif
1452
1453
#define abort() DebugBreak();
1454
1455
#ifndef BUFSIZ
1456
#define BUFSIZ 4096
1457
#endif
1458
/*
1459
 * Explicitly disabling MG_ENABLE_THREADS for WinCE
1460
 * because they are enabled for _WIN32 by default
1461
 */
1462
#ifndef MG_ENABLE_THREADS
1463
#define MG_ENABLE_THREADS 0
1464
#endif
1465
1466
#ifndef MG_ENABLE_FILESYSTEM
1467
#define MG_ENABLE_FILESYSTEM 1
1468
#endif
1469
1470
#ifndef MG_NET_IF
1471
#define MG_NET_IF MG_NET_IF_SOCKET
1472
#endif
1473
1474
typedef struct _stati64 {
1475
  uint32_t st_mtime;
1476
  uint32_t st_size;
1477
  uint32_t st_mode;
1478
} cs_stat_t;
1479
1480
/*
1481
 * WinCE 6.0 has a lot of useful definitions in ATL (not windows.h) headers
1482
 * use #ifdefs to avoid conflicts
1483
 */
1484
1485
#ifndef ENOENT
1486
#define ENOENT ERROR_PATH_NOT_FOUND
1487
#endif
1488
1489
#ifndef EACCES
1490
#define EACCES ERROR_ACCESS_DENIED
1491
#endif
1492
1493
#ifndef ENOMEM
1494
#define ENOMEM ERROR_NOT_ENOUGH_MEMORY
1495
#endif
1496
1497
#ifndef _UINTPTR_T_DEFINED
1498
typedef unsigned int *uintptr_t;
1499
#endif
1500
1501
#define _S_IFREG 2
1502
#define _S_IFDIR 4
1503
1504
#ifndef S_ISDIR
1505
#define S_ISDIR(x) (((x) &_S_IFDIR) != 0)
1506
#endif
1507
1508
#ifndef S_ISREG
1509
#define S_ISREG(x) (((x) &_S_IFREG) != 0)
1510
#endif
1511
1512
int open(const char *filename, int oflag, int pmode);
1513
int _wstati64(const wchar_t *path, cs_stat_t *st);
1514
const char *strerror();
1515
1516
#endif /* CS_PLATFORM == CS_P_WINCE */
1517
#endif /* CS_COMMON_PLATFORMS_PLATFORM_WINCE_H_ */
1518
#ifdef MJS_MODULE_LINES
1519
#line 1 "common/platforms/platform_nxp_lpc.h"
1520
#endif
1521
/*
1522
 * Copyright (c) 2014-2018 Cesanta Software Limited
1523
 * All rights reserved
1524
 *
1525
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1526
 * you may not use this file except in compliance with the License.
1527
 * You may obtain a copy of the License at
1528
 *
1529
 *     http://www.apache.org/licenses/LICENSE-2.0
1530
 *
1531
 * Unless required by applicable law or agreed to in writing, software
1532
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1533
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1534
 * See the License for the specific language governing permissions and
1535
 * limitations under the License.
1536
 */
1537
1538
#ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_
1539
#define CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_
1540
1541
#if CS_PLATFORM == CS_P_NXP_LPC
1542
1543
#include <ctype.h>
1544
#include <stdint.h>
1545
#include <string.h>
1546
1547
#define SIZE_T_FMT "u"
1548
typedef struct stat cs_stat_t;
1549
#define INT64_FMT "lld"
1550
#define INT64_X_FMT "llx"
1551
#define __cdecl
1552
1553
#define MG_LWIP 1
1554
1555
#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
1556
1557
/*
1558
 * LPCXpress comes with 3 C library implementations: Newlib, NewlibNano and
1559
 *Redlib.
1560
 * See https://community.nxp.com/message/630860 for more details.
1561
 *
1562
 * Redlib is the default and lacks certain things, so we provide them.
1563
 */
1564
#ifdef __REDLIB_INTERFACE_VERSION__
1565
1566
/* Let LWIP define timeval for us. */
1567
#define LWIP_TIMEVAL_PRIVATE 1
1568
1569
#define va_copy(d, s) __builtin_va_copy(d, s)
1570
1571
#define CS_ENABLE_TO64 1
1572
#define to64(x) cs_to64(x)
1573
1574
#define CS_ENABLE_STRDUP 1
1575
1576
#else
1577
1578
#include <sys/time.h>
1579
#define LWIP_TIMEVAL_PRIVATE 0
1580
#define to64(x) strtoll(x, NULL, 10)
1581
1582
#endif
1583
1584
#endif /* CS_PLATFORM == CS_P_NXP_LPC */
1585
#endif /* CS_COMMON_PLATFORMS_PLATFORM_NXP_LPC_H_ */
1586
#ifdef MJS_MODULE_LINES
1587
#line 1 "common/platforms/platform_nxp_kinetis.h"
1588
#endif
1589
/*
1590
 * Copyright (c) 2014-2018 Cesanta Software Limited
1591
 * All rights reserved
1592
 *
1593
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1594
 * you may not use this file except in compliance with the License.
1595
 * You may obtain a copy of the License at
1596
 *
1597
 *     http://www.apache.org/licenses/LICENSE-2.0
1598
 *
1599
 * Unless required by applicable law or agreed to in writing, software
1600
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1601
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1602
 * See the License for the specific language governing permissions and
1603
 * limitations under the License.
1604
 */
1605
1606
#ifndef CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_
1607
#define CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_
1608
1609
#if CS_PLATFORM == CS_P_NXP_KINETIS
1610
1611
#include <ctype.h>
1612
#include <inttypes.h>
1613
#include <string.h>
1614
#include <sys/time.h>
1615
1616
#define SIZE_T_FMT "u"
1617
typedef struct stat cs_stat_t;
1618
#define to64(x) strtoll(x, NULL, 10)
1619
#define INT64_FMT "lld"
1620
#define INT64_X_FMT "llx"
1621
#define __cdecl
1622
1623
#define MG_LWIP 1
1624
1625
#define MG_NET_IF MG_NET_IF_LWIP_LOW_LEVEL
1626
1627
/* struct timeval is defined in sys/time.h. */
1628
#define LWIP_TIMEVAL_PRIVATE 0
1629
1630
#endif /* CS_PLATFORM == CS_P_NXP_KINETIS */
1631
#endif /* CS_COMMON_PLATFORMS_PLATFORM_NXP_KINETIS_H_ */
1632
#ifdef MJS_MODULE_LINES
1633
#line 1 "common/platforms/platform_pic32.h"
1634
#endif
1635
/*
1636
 * Copyright (c) 2014-2018 Cesanta Software Limited
1637
 * All rights reserved
1638
 *
1639
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1640
 * you may not use this file except in compliance with the License.
1641
 * You may obtain a copy of the License at
1642
 *
1643
 *     http://www.apache.org/licenses/LICENSE-2.0
1644
 *
1645
 * Unless required by applicable law or agreed to in writing, software
1646
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1647
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1648
 * See the License for the specific language governing permissions and
1649
 * limitations under the License.
1650
 */
1651
1652
#ifndef CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_
1653
#define CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_
1654
1655
#if CS_PLATFORM == CS_P_PIC32
1656
1657
#define MG_NET_IF MG_NET_IF_PIC32
1658
1659
#include <stdint.h>
1660
#include <time.h>
1661
#include <ctype.h>
1662
#include <stdlib.h>
1663
1664
#include <system_config.h>
1665
#include <system_definitions.h>
1666
1667
#include <sys/types.h>
1668
1669
typedef TCP_SOCKET sock_t;
1670
#define to64(x) strtoll(x, NULL, 10)
1671
1672
#define SIZE_T_FMT "lu"
1673
#define INT64_FMT "lld"
1674
1675
#ifndef CS_ENABLE_STDIO
1676
#define CS_ENABLE_STDIO 1
1677
#endif
1678
1679
char *inet_ntoa(struct in_addr in);
1680
1681
#endif /* CS_PLATFORM == CS_P_PIC32 */
1682
1683
#endif /* CS_COMMON_PLATFORMS_PLATFORM_PIC32_H_ */
1684
#ifdef MJS_MODULE_LINES
1685
#line 1 "common/platforms/platform_stm32.h"
1686
#endif
1687
/*
1688
 * Copyright (c) 2014-2018 Cesanta Software Limited
1689
 * All rights reserved
1690
 *
1691
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1692
 * you may not use this file except in compliance with the License.
1693
 * You may obtain a copy of the License at
1694
 *
1695
 *     http://www.apache.org/licenses/LICENSE-2.0
1696
 *
1697
 * Unless required by applicable law or agreed to in writing, software
1698
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1699
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1700
 * See the License for the specific language governing permissions and
1701
 * limitations under the License.
1702
 */
1703
1704
#ifndef CS_COMMON_PLATFORMS_PLATFORM_STM32_H_
1705
#define CS_COMMON_PLATFORMS_PLATFORM_STM32_H_
1706
#if CS_PLATFORM == CS_P_STM32
1707
1708
#include <ctype.h>
1709
#include <errno.h>
1710
#include <fcntl.h>
1711
#include <stdint.h>
1712
#include <stdio.h>
1713
#include <string.h>
1714
#include <sys/stat.h>
1715
#include <sys/time.h>
1716
#include <sys/types.h>
1717
#include <unistd.h>
1718
#include <dirent.h>
1719
1720
#include <stm32_sdk_hal.h>
1721
1722
#define to64(x) strtoll(x, NULL, 10)
1723
#define INT64_FMT PRId64
1724
#define SIZE_T_FMT "u"
1725
typedef struct stat cs_stat_t;
1726
#define DIRSEP '/'
1727
1728
#ifndef CS_ENABLE_STDIO
1729
#define CS_ENABLE_STDIO 1
1730
#endif
1731
1732
#ifndef MG_ENABLE_FILESYSTEM
1733
#define MG_ENABLE_FILESYSTEM 1
1734
#endif
1735
1736
#endif /* CS_PLATFORM == CS_P_STM32 */
1737
#endif /* CS_COMMON_PLATFORMS_PLATFORM_STM32_H_ */
1738
#ifdef MJS_MODULE_LINES
1739
#line 1 "common/cs_dbg.h"
1740
#endif
1741
/*
1742
 * Copyright (c) 2014-2018 Cesanta Software Limited
1743
 * All rights reserved
1744
 *
1745
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1746
 * you may not use this file except in compliance with the License.
1747
 * You may obtain a copy of the License at
1748
 *
1749
 *     http://www.apache.org/licenses/LICENSE-2.0
1750
 *
1751
 * Unless required by applicable law or agreed to in writing, software
1752
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1753
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1754
 * See the License for the specific language governing permissions and
1755
 * limitations under the License.
1756
 */
1757
1758
#ifndef CS_COMMON_CS_DBG_H_
1759
#define CS_COMMON_CS_DBG_H_
1760
1761
/* Amalgamated: #include "common/platform.h" */
1762
1763
#if CS_ENABLE_STDIO
1764
#include <stdio.h>
1765
#endif
1766
1767
#ifndef CS_ENABLE_DEBUG
1768
#define CS_ENABLE_DEBUG 0
1769
#endif
1770
1771
#ifndef CS_LOG_ENABLE_TS_DIFF
1772
#define CS_LOG_ENABLE_TS_DIFF 0
1773
#endif
1774
1775
#ifdef __cplusplus
1776
extern "C" {
1777
#endif /* __cplusplus */
1778
1779
/*
1780
 * Log level; `LL_INFO` is the default. Use `cs_log_set_level()` to change it.
1781
 */
1782
enum cs_log_level {
1783
  LL_NONE = -1,
1784
  LL_ERROR = 0,
1785
  LL_WARN = 1,
1786
  LL_INFO = 2,
1787
  LL_DEBUG = 3,
1788
  LL_VERBOSE_DEBUG = 4,
1789
1790
  _LL_MIN = -2,
1791
  _LL_MAX = 5,
1792
};
1793
1794
/*
1795
 * Set max log level to print; messages with the level above the given one will
1796
 * not be printed.
1797
 */
1798
void cs_log_set_level(enum cs_log_level level);
1799
1800
/*
1801
 * Set log filter. NULL (a default) logs everything.
1802
 * Otherwise, function name and file name will be tested against the given
1803
 * pattern, and only matching messages will be printed.
1804
 *
1805
 * For the pattern syntax, refer to `mg_match_prefix()` in `str_util.h`.
1806
 *
1807
 * Example:
1808
 * ```c
1809
 * void foo(void) {
1810
 *   LOG(LL_INFO, ("hello from foo"));
1811
 * }
1812
 *
1813
 * void bar(void) {
1814
 *   LOG(LL_INFO, ("hello from bar"));
1815
 * }
1816
 *
1817
 * void test(void) {
1818
 *   cs_log_set_filter(NULL);
1819
 *   foo();
1820
 *   bar();
1821
 *
1822
 *   cs_log_set_filter("f*");
1823
 *   foo();
1824
 *   bar(); // Will NOT print anything
1825
 *
1826
 *   cs_log_set_filter("bar");
1827
 *   foo(); // Will NOT print anything
1828
 *   bar();
1829
 * }
1830
 * ```
1831
 */
1832
void cs_log_set_filter(const char *pattern);
1833
1834
/*
1835
 * Helper function which prints message prefix with the given `level`, function
1836
 * name `func` and `filename`. If message should be printed (accordingly to the
1837
 * current log level and filter), prints the prefix and returns 1, otherwise
1838
 * returns 0.
1839
 *
1840
 * Clients should typically just use `LOG()` macro.
1841
 */
1842
int cs_log_print_prefix(enum cs_log_level level, const char *func,
1843
                        const char *filename);
1844
1845
extern enum cs_log_level cs_log_threshold;
1846
1847
#if CS_ENABLE_STDIO
1848
1849
/*
1850
 * Set file to write logs into. If `NULL`, logs go to `stderr`.
1851
 */
1852
void cs_log_set_file(FILE *file);
1853
1854
/*
1855
 * Prints log to the current log file, appends "\n" in the end and flushes the
1856
 * stream.
1857
 */
1858
void cs_log_printf(const char *fmt, ...) PRINTF_LIKE(1, 2);
1859
1860
/*
1861
 * Format and print message `x` with the given level `l`. Example:
1862
 *
1863
 * ```c
1864
 * LOG(LL_INFO, ("my info message: %d", 123));
1865
 * LOG(LL_DEBUG, ("my debug message: %d", 123));
1866
 * ```
1867
 */
1868
#define LOG(l, x)                                                    \
1869
  do {                                                               \
1870
    if (cs_log_print_prefix(l, __func__, __FILE__)) cs_log_printf x; \
1871
  } while (0)
1872
1873
#ifndef CS_NDEBUG
1874
1875
/*
1876
 * Shortcut for `LOG(LL_VERBOSE_DEBUG, (...))`
1877
 */
1878
#define DBG(x) LOG(LL_VERBOSE_DEBUG, x)
1879
1880
#else /* NDEBUG */
1881
1882
#define DBG(x)
1883
1884
#endif
1885
1886
#else /* CS_ENABLE_STDIO */
1887
1888
#define LOG(l, x)
1889
#define DBG(x)
1890
1891
#endif
1892
1893
#ifdef __cplusplus
1894
}
1895
#endif /* __cplusplus */
1896
1897
#endif /* CS_COMMON_CS_DBG_H_ */
1898
#ifdef MJS_MODULE_LINES
1899
#line 1 "common/cs_time.h"
1900
#endif
1901
/*
1902
 * Copyright (c) 2014-2018 Cesanta Software Limited
1903
 * All rights reserved
1904
 *
1905
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1906
 * you may not use this file except in compliance with the License.
1907
 * You may obtain a copy of the License at
1908
 *
1909
 *     http://www.apache.org/licenses/LICENSE-2.0
1910
 *
1911
 * Unless required by applicable law or agreed to in writing, software
1912
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1913
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1914
 * See the License for the specific language governing permissions and
1915
 * limitations under the License.
1916
 */
1917
1918
#ifndef CS_COMMON_CS_TIME_H_
1919
#define CS_COMMON_CS_TIME_H_
1920
1921
#include <time.h>
1922
1923
/* Amalgamated: #include "common/platform.h" */
1924
1925
#ifdef __cplusplus
1926
extern "C" {
1927
#endif /* __cplusplus */
1928
1929
/* Sub-second granularity time(). */
1930
double cs_time(void);
1931
1932
/*
1933
 * Similar to (non-standard) timegm, converts broken-down time into the number
1934
 * of seconds since Unix Epoch.
1935
 */
1936
double cs_timegm(const struct tm *tm);
1937
1938
#ifdef __cplusplus
1939
}
1940
#endif /* __cplusplus */
1941
1942
#endif /* CS_COMMON_CS_TIME_H_ */
1943
#ifdef MJS_MODULE_LINES
1944
#line 1 "common/mg_str.h"
1945
#endif
1946
/*
1947
 * Copyright (c) 2014-2018 Cesanta Software Limited
1948
 * All rights reserved
1949
 *
1950
 * Licensed under the Apache License, Version 2.0 (the ""License"");
1951
 * you may not use this file except in compliance with the License.
1952
 * You may obtain a copy of the License at
1953
 *
1954
 *     http://www.apache.org/licenses/LICENSE-2.0
1955
 *
1956
 * Unless required by applicable law or agreed to in writing, software
1957
 * distributed under the License is distributed on an ""AS IS"" BASIS,
1958
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1959
 * See the License for the specific language governing permissions and
1960
 * limitations under the License.
1961
 */
1962
1963
#ifndef CS_COMMON_MG_STR_H_
1964
#define CS_COMMON_MG_STR_H_
1965
1966
#include <stddef.h>
1967
1968
#ifdef __cplusplus
1969
extern "C" {
1970
#endif
1971
1972
/* Describes chunk of memory */
1973
struct mg_str {
1974
  const char *p; /* Memory chunk pointer */
1975
  size_t len;    /* Memory chunk length */
1976
};
1977
1978
/*
1979
 * Helper function for creating mg_str struct from plain C string.
1980
 * `NULL` is allowed and becomes `{NULL, 0}`.
1981
 */
1982
struct mg_str mg_mk_str(const char *s);
1983
1984
/*
1985
 * Like `mg_mk_str`, but takes string length explicitly.
1986
 */
1987
struct mg_str mg_mk_str_n(const char *s, size_t len);
1988
1989
/* Macro for initializing mg_str. */
1990
#define MG_MK_STR(str_literal) \
1991
  { str_literal, sizeof(str_literal) - 1 }
1992
#define MG_NULL_STR \
1993
  { NULL, 0 }
1994
1995
/*
1996
 * Cross-platform version of `strcmp()` where where first string is
1997
 * specified by `struct mg_str`.
1998
 */
1999
int mg_vcmp(const struct mg_str *str2, const char *str1);
2000
2001
/*
2002
 * Cross-platform version of `strncasecmp()` where first string is
2003
 * specified by `struct mg_str`.
2004
 */
2005
int mg_vcasecmp(const struct mg_str *str2, const char *str1);
2006
2007
/* Creates a copy of s (heap-allocated). */
2008
struct mg_str mg_strdup(const struct mg_str s);
2009
2010
/*
2011
 * Creates a copy of s (heap-allocated).
2012
 * Resulting string is NUL-terminated (but NUL is not included in len).
2013
 */
2014
struct mg_str mg_strdup_nul(const struct mg_str s);
2015
2016
/*
2017
 * Locates character in a string.
2018
 */
2019
const char *mg_strchr(const struct mg_str s, int c);
2020
2021
/*
2022
 * Compare two `mg_str`s; return value is the same as `strcmp`.
2023
 */
2024
int mg_strcmp(const struct mg_str str1, const struct mg_str str2);
2025
2026
/*
2027
 * Like `mg_strcmp`, but compares at most `n` characters.
2028
 */
2029
int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n);
2030
2031
/*
2032
 * Finds the first occurrence of a substring `needle` in the `haystack`.
2033
 */
2034
const char *mg_strstr(const struct mg_str haystack, const struct mg_str needle);
2035
2036
#ifdef __cplusplus
2037
}
2038
#endif
2039
2040
#endif /* CS_COMMON_MG_STR_H_ */
2041
#ifdef MJS_MODULE_LINES
2042
#line 1 "common/str_util.h"
2043
#endif
2044
/*
2045
 * Copyright (c) 2014-2018 Cesanta Software Limited
2046
 * All rights reserved
2047
 *
2048
 * Licensed under the Apache License, Version 2.0 (the ""License"");
2049
 * you may not use this file except in compliance with the License.
2050
 * You may obtain a copy of the License at
2051
 *
2052
 *     http://www.apache.org/licenses/LICENSE-2.0
2053
 *
2054
 * Unless required by applicable law or agreed to in writing, software
2055
 * distributed under the License is distributed on an ""AS IS"" BASIS,
2056
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2057
 * See the License for the specific language governing permissions and
2058
 * limitations under the License.
2059
 */
2060
2061
#ifndef CS_COMMON_STR_UTIL_H_
2062
#define CS_COMMON_STR_UTIL_H_
2063
2064
#include <stdarg.h>
2065
#include <stdlib.h>
2066
2067
/* Amalgamated: #include "common/mg_str.h" */
2068
/* Amalgamated: #include "common/platform.h" */
2069
2070
#ifndef CS_ENABLE_STRDUP
2071
#define CS_ENABLE_STRDUP 0
2072
#endif
2073
2074
#ifndef CS_ENABLE_TO64
2075
#define CS_ENABLE_TO64 0
2076
#endif
2077
2078
/*
2079
 * Expands to a string representation of its argument: e.g.
2080
 * `CS_STRINGIFY_LIT(5) expands to "5"`
2081
 */
2082
#define CS_STRINGIFY_LIT(x) #x
2083
2084
/*
2085
 * Expands to a string representation of its argument, which is allowed
2086
 * to be a macro: e.g.
2087
 *
2088
 * #define FOO 123
2089
 * CS_STRINGIFY_MACRO(FOO)
2090
 *
2091
 * expands to 123.
2092
 */
2093
#define CS_STRINGIFY_MACRO(x) CS_STRINGIFY_LIT(x)
2094
2095
#ifdef __cplusplus
2096
extern "C" {
2097
#endif
2098
2099
/*
2100
 * Equivalent of standard `strnlen()`.
2101
 */
2102
size_t c_strnlen(const char *s, size_t maxlen);
2103
2104
/*
2105
 * Equivalent of standard `snprintf()`.
2106
 */
2107
int c_snprintf(char *buf, size_t buf_size, const char *format, ...)
2108
    PRINTF_LIKE(3, 4);
2109
2110
/*
2111
 * Equivalent of standard `vsnprintf()`.
2112
 */
2113
int c_vsnprintf(char *buf, size_t buf_size, const char *format, va_list ap);
2114
2115
/*
2116
 * Find the first occurrence of find in s, where the search is limited to the
2117
 * first slen characters of s.
2118
 */
2119
const char *c_strnstr(const char *s, const char *find, size_t slen);
2120
2121
/*
2122
 * Stringify binary data. Output buffer size must be 2 * size_of_input + 1
2123
 * because each byte of input takes 2 bytes in string representation
2124
 * plus 1 byte for the terminating \0 character.
2125
 */
2126
void cs_to_hex(char *to, const unsigned char *p, size_t len);
2127
2128
/*
2129
 * Convert stringified binary data back to binary.
2130
 * Does the reverse of `cs_to_hex()`.
2131
 */
2132
void cs_from_hex(char *to, const char *p, size_t len);
2133
2134
#if CS_ENABLE_STRDUP
2135
/*
2136
 * Equivalent of standard `strdup()`, defined if only `CS_ENABLE_STRDUP` is 1.
2137
 */
2138
char *strdup(const char *src);
2139
#endif
2140
2141
#if CS_ENABLE_TO64
2142
#include <stdint.h>
2143
/*
2144
 * Simple string -> int64 conversion routine.
2145
 */
2146
int64_t cs_to64(const char *s);
2147
#endif
2148
2149
/*
2150
 * Cross-platform version of `strncasecmp()`.
2151
 */
2152
int mg_ncasecmp(const char *s1, const char *s2, size_t len);
2153
2154
/*
2155
 * Cross-platform version of `strcasecmp()`.
2156
 */
2157
int mg_casecmp(const char *s1, const char *s2);
2158
2159
/*
2160
 * Prints message to the buffer. If the buffer is large enough to hold the
2161
 * message, it returns buffer. If buffer is to small, it allocates a large
2162
 * enough buffer on heap and returns allocated buffer.
2163
 * This is a supposed use case:
2164
 *
2165
 * ```c
2166
 *    char buf[5], *p = buf;
2167
 *    mg_avprintf(&p, sizeof(buf), "%s", "hi there");
2168
 *    use_p_somehow(p);
2169
 *    if (p != buf) {
2170
 *      free(p);
2171
 *    }
2172
 * ```
2173
 *
2174
 * The purpose of this is to avoid malloc-ing if generated strings are small.
2175
 */
2176
int mg_asprintf(char **buf, size_t size, const char *fmt, ...)
2177
    PRINTF_LIKE(3, 4);
2178
2179
/* Same as mg_asprintf, but takes varargs list. */
2180
int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap);
2181
2182
/*
2183
 * A helper function for traversing a comma separated list of values.
2184
 * It returns a list pointer shifted to the next value or NULL if the end
2185
 * of the list found.
2186
 * The value is stored in a val vector. If the value has a form "x=y", then
2187
 * eq_val vector is initialised to point to the "y" part, and val vector length
2188
 * is adjusted to point only to "x".
2189
 * If the list is just a comma separated list of entries, like "aa,bb,cc" then
2190
 * `eq_val` will contain zero-length string.
2191
 *
2192
 * The purpose of this function is to parse comma separated string without
2193
 * any copying/memory allocation.
2194
 */
2195
const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
2196
                                     struct mg_str *eq_val);
2197
2198
/*
2199
 * Like `mg_next_comma_list_entry()`, but takes `list` as `struct mg_str`.
2200
 */
2201
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
2202
                                         struct mg_str *eq_val);
2203
2204
/*
2205
 * Matches 0-terminated string (mg_match_prefix) or string with given length
2206
 * mg_match_prefix_n against a glob pattern. Glob syntax:
2207
 * ```
2208
 * - * matches zero or more characters until a slash character /
2209
 * - ** matches zero or more characters
2210
 * - ? Matches exactly one character which is not a slash /
2211
 * - | or ,  divides alternative patterns
2212
 * - any other character matches itself
2213
 * ```
2214
 * Match is case-insensitive. Return number of bytes matched.
2215
 * Examples:
2216
 * ```
2217
 * mg_match_prefix("a*f", len, "abcdefgh") == 6
2218
 * mg_match_prefix("a*f", len, "abcdexgh") == 0
2219
 * mg_match_prefix("a*f|de*,xy", len, "defgh") == 5
2220
 * mg_match_prefix("?*", len, "abc") == 3
2221
 * mg_match_prefix("?*", len, "") == 0
2222
 * ```
2223
 */
2224
size_t mg_match_prefix(const char *pattern, int pattern_len, const char *str);
2225
2226
/*
2227
 * Like `mg_match_prefix()`, but takes `pattern` and `str` as `struct mg_str`.
2228
 */
2229
size_t mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str);
2230
2231
#ifdef __cplusplus
2232
}
2233
#endif
2234
2235
#endif /* CS_COMMON_STR_UTIL_H_ */
2236
#ifdef MJS_MODULE_LINES
2237
#line 1 "common/cs_file.h"
2238
#endif
2239
/*
2240
 * Copyright (c) 2014-2018 Cesanta Software Limited
2241
 * All rights reserved
2242
 *
2243
 * Licensed under the Apache License, Version 2.0 (the ""License"");
2244
 * you may not use this file except in compliance with the License.
2245
 * You may obtain a copy of the License at
2246
 *
2247
 *     http://www.apache.org/licenses/LICENSE-2.0
2248
 *
2249
 * Unless required by applicable law or agreed to in writing, software
2250
 * distributed under the License is distributed on an ""AS IS"" BASIS,
2251
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2252
 * See the License for the specific language governing permissions and
2253
 * limitations under the License.
2254
 */
2255
2256
#ifndef CS_COMMON_CS_FILE_H_
2257
#define CS_COMMON_CS_FILE_H_
2258
2259
/* Amalgamated: #include "common/platform.h" */
2260
2261
#ifdef __cplusplus
2262
extern "C" {
2263
#endif /* __cplusplus */
2264
2265
/*
2266
 * Read whole file `path` in memory. It is responsibility of the caller
2267
 * to `free()` allocated memory. File content is guaranteed to be
2268
 * '\0'-terminated. File size is returned in `size` variable, which does not
2269
 * count terminating `\0`.
2270
 * Return: allocated memory, or NULL on error.
2271
 */
2272
char *cs_read_file(const char *path, size_t *size);
2273
2274
#ifdef CS_MMAP
2275
/*
2276
 * Only on platforms which support mmapping: mmap file `path` to the returned
2277
 * address. File size is written to `*size`.
2278
 */
2279
char *cs_mmap_file(const char *path, size_t *size);
2280
#endif
2281
2282
#ifdef __cplusplus
2283
}
2284
#endif /* __cplusplus */
2285
2286
#endif /* CS_COMMON_CS_FILE_H_ */
2287
#ifdef MJS_MODULE_LINES
2288
#line 1 "common/mbuf.h"
2289
#endif
2290
/*
2291
 * Copyright (c) 2014-2018 Cesanta Software Limited
2292
 * All rights reserved
2293
 *
2294
 * Licensed under the Apache License, Version 2.0 (the ""License"");
2295
 * you may not use this file except in compliance with the License.
2296
 * You may obtain a copy of the License at
2297
 *
2298
 *     http://www.apache.org/licenses/LICENSE-2.0
2299
 *
2300
 * Unless required by applicable law or agreed to in writing, software
2301
 * distributed under the License is distributed on an ""AS IS"" BASIS,
2302
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2303
 * See the License for the specific language governing permissions and
2304
 * limitations under the License.
2305
 */
2306
2307
/*
2308
 * === Memory Buffers
2309
 *
2310
 * Mbufs are mutable/growing memory buffers, like C++ strings.
2311
 * Mbuf can append data to the end of a buffer or insert data into arbitrary
2312
 * position in the middle of a buffer. The buffer grows automatically when
2313
 * needed.
2314
 */
2315
2316
#ifndef CS_COMMON_MBUF_H_
2317
#define CS_COMMON_MBUF_H_
2318
2319
#include <stdlib.h>
2320
/* Amalgamated: #include "common/platform.h" */
2321
2322
#if defined(__cplusplus)
2323
extern "C" {
2324
#endif
2325
2326
#ifndef MBUF_SIZE_MULTIPLIER
2327
#define MBUF_SIZE_MULTIPLIER 1.5
2328
#endif
2329
2330
#ifndef MBUF_SIZE_MAX_HEADROOM
2331
#ifdef BUFSIZ
2332
#define MBUF_SIZE_MAX_HEADROOM BUFSIZ
2333
#else
2334
#define MBUF_SIZE_MAX_HEADROOM 1024
2335
#endif
2336
#endif
2337
2338
/* Memory buffer descriptor */
2339
struct mbuf {
2340
  char *buf;   /* Buffer pointer */
2341
  size_t len;  /* Data length. Data is located between offset 0 and len. */
2342
  size_t size; /* Buffer size allocated by realloc(1). Must be >= len */
2343
};
2344
2345
/*
2346
 * Initialises an Mbuf.
2347
 * `initial_capacity` specifies the initial capacity of the mbuf.
2348
 */
2349
void mbuf_init(struct mbuf *, size_t initial_capacity);
2350
2351
/* Frees the space allocated for the mbuffer and resets the mbuf structure. */
2352
void mbuf_free(struct mbuf *);
2353
2354
/*
2355
 * Appends data to the Mbuf.
2356
 *
2357
 * Returns the number of bytes appended or 0 if out of memory.
2358
 */
2359
size_t mbuf_append(struct mbuf *, const void *data, size_t data_size);
2360
2361
/*
2362
 * Inserts data at a specified offset in the Mbuf.
2363
 *
2364
 * Existing data will be shifted forwards and the buffer will
2365
 * be grown if necessary.
2366
 * Returns the number of bytes inserted.
2367
 */
2368
size_t mbuf_insert(struct mbuf *, size_t, const void *, size_t);
2369
2370
/* Removes `data_size` bytes from the beginning of the buffer. */
2371
void mbuf_remove(struct mbuf *, size_t data_size);
2372
2373
/*
2374
 * Resizes an Mbuf.
2375
 *
2376
 * If `new_size` is smaller than buffer's `len`, the
2377
 * resize is not performed.
2378
 */
2379
void mbuf_resize(struct mbuf *, size_t new_size);
2380
2381
/* Shrinks an Mbuf by resizing its `size` to `len`. */
2382
void mbuf_trim(struct mbuf *);
2383
2384
#if defined(__cplusplus)
2385
}
2386
#endif /* __cplusplus */
2387
2388
#endif /* CS_COMMON_MBUF_H_ */
2389
#ifdef MJS_MODULE_LINES
2390
#line 1 "common/mg_mem.h"
2391
#endif
2392
/*
2393
 * Copyright (c) 2014-2018 Cesanta Software Limited
2394
 * All rights reserved
2395
 *
2396
 * Licensed under the Apache License, Version 2.0 (the ""License"");
2397
 * you may not use this file except in compliance with the License.
2398
 * You may obtain a copy of the License at
2399
 *
2400
 *     http://www.apache.org/licenses/LICENSE-2.0
2401
 *
2402
 * Unless required by applicable law or agreed to in writing, software
2403
 * distributed under the License is distributed on an ""AS IS"" BASIS,
2404
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2405
 * See the License for the specific language governing permissions and
2406
 * limitations under the License.
2407
 */
2408
2409
#ifndef CS_COMMON_MG_MEM_H_
2410
#define CS_COMMON_MG_MEM_H_
2411
2412
#ifdef __cplusplus
2413
extern "C" {
2414
#endif
2415
2416
#ifndef MG_MALLOC
2417
#define MG_MALLOC malloc
2418
#endif
2419
2420
#ifndef MG_CALLOC
2421
#define MG_CALLOC calloc
2422
#endif
2423
2424
#ifndef MG_REALLOC
2425
#define MG_REALLOC realloc
2426
#endif
2427
2428
#ifndef MG_FREE
2429
#define MG_FREE free
2430
#endif
2431
2432
#ifdef __cplusplus
2433
}
2434
#endif
2435
2436
#endif /* CS_COMMON_MG_MEM_H_ */
2437
#ifdef MJS_MODULE_LINES
2438
#line 1 "frozen/frozen.h"
2439
#endif
2440
/*
2441
 * Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
2442
 * Copyright (c) 2018 Cesanta Software Limited
2443
 * All rights reserved
2444
 *
2445
 * Licensed under the Apache License, Version 2.0 (the ""License"");
2446
 * you may not use this file except in compliance with the License.
2447
 * You may obtain a copy of the License at
2448
 *
2449
 *     http://www.apache.org/licenses/LICENSE-2.0
2450
 *
2451
 * Unless required by applicable law or agreed to in writing, software
2452
 * distributed under the License is distributed on an ""AS IS"" BASIS,
2453
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2454
 * See the License for the specific language governing permissions and
2455
 * limitations under the License.
2456
 */
2457
2458
#ifndef CS_FROZEN_FROZEN_H_
2459
#define CS_FROZEN_FROZEN_H_
2460
2461
#ifdef __cplusplus
2462
extern "C" {
2463
#endif /* __cplusplus */
2464
2465
#include <stdarg.h>
2466
#include <stddef.h>
2467
#include <stdio.h>
2468
2469
#if defined(_WIN32) && _MSC_VER < 1700
2470
typedef int bool;
2471
enum { false = 0, true = 1 };
2472
#else
2473
#include <stdbool.h>
2474
#endif
2475
2476
/* JSON token type */
2477
enum json_token_type {
2478
  JSON_TYPE_INVALID = 0, /* memsetting to 0 should create INVALID value */
2479
  JSON_TYPE_STRING,
2480
  JSON_TYPE_NUMBER,
2481
  JSON_TYPE_TRUE,
2482
  JSON_TYPE_FALSE,
2483
  JSON_TYPE_NULL,
2484
  JSON_TYPE_OBJECT_START,
2485
  JSON_TYPE_OBJECT_END,
2486
  JSON_TYPE_ARRAY_START,
2487
  JSON_TYPE_ARRAY_END,
2488
2489
  JSON_TYPES_CNT
2490
};
2491
2492
/*
2493
 * Structure containing token type and value. Used in `json_walk()` and
2494
 * `json_scanf()` with the format specifier `%T`.
2495
 */
2496
struct json_token {
2497
  const char *ptr;           /* Points to the beginning of the value */
2498
  int len;                   /* Value length */
2499
  enum json_token_type type; /* Type of the token, possible values are above */
2500
};
2501
2502
#define JSON_INVALID_TOKEN \
2503
  { 0, 0, JSON_TYPE_INVALID }
2504
2505
/* Error codes */
2506
#define JSON_STRING_INVALID -1
2507
#define JSON_STRING_INCOMPLETE -2
2508
2509
/*
2510
 * Callback-based SAX-like API.
2511
 *
2512
 * Property name and length is given only if it's available: i.e. if current
2513
 * event is an object's property. In other cases, `name` is `NULL`. For
2514
 * example, name is never given:
2515
 *   - For the first value in the JSON string;
2516
 *   - For events JSON_TYPE_OBJECT_END and JSON_TYPE_ARRAY_END
2517
 *
2518
 * E.g. for the input `{ "foo": 123, "bar": [ 1, 2, { "baz": true } ] }`,
2519
 * the sequence of callback invocations will be as follows:
2520
 *
2521
 * - type: JSON_TYPE_OBJECT_START, name: NULL, path: "", value: NULL
2522
 * - type: JSON_TYPE_NUMBER, name: "foo", path: ".foo", value: "123"
2523
 * - type: JSON_TYPE_ARRAY_START,  name: "bar", path: ".bar", value: NULL
2524
 * - type: JSON_TYPE_NUMBER, name: "0", path: ".bar[0]", value: "1"
2525
 * - type: JSON_TYPE_NUMBER, name: "1", path: ".bar[1]", value: "2"
2526
 * - type: JSON_TYPE_OBJECT_START, name: "2", path: ".bar[2]", value: NULL
2527
 * - type: JSON_TYPE_TRUE, name: "baz", path: ".bar[2].baz", value: "true"
2528
 * - type: JSON_TYPE_OBJECT_END, name: NULL, path: ".bar[2]", value: "{ \"baz\":
2529
 *true }"
2530
 * - type: JSON_TYPE_ARRAY_END, name: NULL, path: ".bar", value: "[ 1, 2, {
2531
 *\"baz\": true } ]"
2532
 * - type: JSON_TYPE_OBJECT_END, name: NULL, path: "", value: "{ \"foo\": 123,
2533
 *\"bar\": [ 1, 2, { \"baz\": true } ] }"
2534
 */
2535
typedef void (*json_walk_callback_t)(void *callback_data, const char *name,
2536
                                     size_t name_len, const char *path,
2537
                                     const struct json_token *token);
2538
2539
/*
2540
 * Parse `json_string`, invoking `callback` in a way similar to SAX parsers;
2541
 * see `json_walk_callback_t`.
2542
 * Return number of processed bytes, or a negative error code.
2543
 */
2544
int json_walk(const char *json_string, int json_string_length,
2545
              json_walk_callback_t callback, void *callback_data);
2546
2547
/*
2548
 * JSON generation API.
2549
 * struct json_out abstracts output, allowing alternative printing plugins.
2550
 */
2551
struct json_out {
2552
  int (*printer)(struct json_out *, const char *str, size_t len);
2553
  union {
2554
    struct {
2555
      char *buf;
2556
      size_t size;
2557
      size_t len;
2558
    } buf;
2559
    void *data;
2560
    FILE *fp;
2561
  } u;
2562
};
2563
2564
extern int json_printer_buf(struct json_out *, const char *, size_t);
2565
extern int json_printer_file(struct json_out *, const char *, size_t);
2566
2567
#define JSON_OUT_BUF(buf, len) \
2568
  {                            \
2569
    json_printer_buf, {        \
2570
      { buf, len, 0 }          \
2571
    }                          \
2572
  }
2573
#define JSON_OUT_FILE(fp)   \
2574
  {                         \
2575
    json_printer_file, {    \
2576
      { (char *) fp, 0, 0 } \
2577
    }                       \
2578
  }
2579
2580
typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap);
2581
2582
/*
2583
 * Generate formatted output into a given sting buffer.
2584
 * This is a superset of printf() function, with extra format specifiers:
2585
 *  - `%B` print json boolean, `true` or `false`. Accepts an `int`.
2586
 *  - `%Q` print quoted escaped string or `null`. Accepts a `const char *`.
2587
 *  - `%.*Q` same as `%Q`, but with length. Accepts `int`, `const char *`
2588
 *  - `%V` print quoted base64-encoded string. Accepts a `const char *`, `int`.
2589
 *  - `%H` print quoted hex-encoded string. Accepts a `int`, `const char *`.
2590
 *  - `%M` invokes a json_printf_callback_t function. That callback function
2591
 *  can consume more parameters.
2592
 *
2593
 * Return number of bytes printed. If the return value is bigger than the
2594
 * supplied buffer, that is an indicator of overflow. In the overflow case,
2595
 * overflown bytes are not printed.
2596
 */
2597
int json_printf(struct json_out *, const char *fmt, ...);
2598
int json_vprintf(struct json_out *, const char *fmt, va_list ap);
2599
2600
/*
2601
 * Same as json_printf, but prints to a file.
2602
 * File is created if does not exist. File is truncated if already exists.
2603
 */
2604
int json_fprintf(const char *file_name, const char *fmt, ...);
2605
int json_vfprintf(const char *file_name, const char *fmt, va_list ap);
2606
2607
/*
2608
 * Print JSON into an allocated 0-terminated string.
2609
 * Return allocated string, or NULL on error.
2610
 * Example:
2611
 *
2612
 * ```c
2613
 *   char *str = json_asprintf("{a:%H}", 3, "abc");
2614
 *   printf("%s\n", str);  // Prints "616263"
2615
 *   free(str);
2616
 * ```
2617
 */
2618
char *json_asprintf(const char *fmt, ...);
2619
char *json_vasprintf(const char *fmt, va_list ap);
2620
2621
/*
2622
 * Helper %M callback that prints contiguous C arrays.
2623
 * Consumes void *array_ptr, size_t array_size, size_t elem_size, char *fmt
2624
 * Return number of bytes printed.
2625
 */
2626
int json_printf_array(struct json_out *, va_list *ap);
2627
2628
/*
2629
 * Scan JSON string `str`, performing scanf-like conversions according to `fmt`.
2630
 * This is a `scanf()` - like function, with following differences:
2631
 *
2632
 * 1. Object keys in the format string may be not quoted, e.g. "{key: %d}"
2633
 * 2. Order of keys in an object is irrelevant.
2634
 * 3. Several extra format specifiers are supported:
2635
 *    - %B: consumes `int *` (or `char *`, if `sizeof(bool) == sizeof(char)`),
2636
 *       expects boolean `true` or `false`.
2637
 *    - %Q: consumes `char **`, expects quoted, JSON-encoded string. Scanned
2638
 *       string is malloc-ed, caller must free() the string.
2639
 *    - %V: consumes `char **`, `int *`. Expects base64-encoded string.
2640
 *       Result string is base64-decoded, malloced and NUL-terminated.
2641
 *       The length of result string is stored in `int *` placeholder.
2642
 *       Caller must free() the result.
2643
 *    - %H: consumes `int *`, `char **`.
2644
 *       Expects a hex-encoded string, e.g. "fa014f".
2645
 *       Result string is hex-decoded, malloced and NUL-terminated.
2646
 *       The length of the result string is stored in `int *` placeholder.
2647
 *       Caller must free() the result.
2648
 *    - %M: consumes custom scanning function pointer and
2649
 *       `void *user_data` parameter - see json_scanner_t definition.
2650
 *    - %T: consumes `struct json_token *`, fills it out with matched token.
2651
 *
2652
 * Return number of elements successfully scanned & converted.
2653
 * Negative number means scan error.
2654
 */
2655
int json_scanf(const char *str, int str_len, const char *fmt, ...);
2656
int json_vscanf(const char *str, int str_len, const char *fmt, va_list ap);
2657
2658
/* json_scanf's %M handler  */
2659
typedef void (*json_scanner_t)(const char *str, int len, void *user_data);
2660
2661
/*
2662
 * Helper function to scan array item with given path and index.
2663
 * Fills `token` with the matched JSON token.
2664
 * Return -1 if no array element found, otherwise non-negative token length.
2665
 */
2666
int json_scanf_array_elem(const char *s, int len, const char *path, int index,
2667
                          struct json_token *token);
2668
2669
/*
2670
 * Unescape JSON-encoded string src,slen into dst, dlen.
2671
 * src and dst may overlap.
2672
 * If destination buffer is too small (or zero-length), result string is not
2673
 * written but the length is counted nevertheless (similar to snprintf).
2674
 * Return the length of unescaped string in bytes.
2675
 */
2676
int json_unescape(const char *src, int slen, char *dst, int dlen);
2677
2678
/*
2679
 * Escape a string `str`, `str_len` into the printer `out`.
2680
 * Return the number of bytes printed.
2681
 */
2682
int json_escape(struct json_out *out, const char *str, size_t str_len);
2683
2684
/*
2685
 * Read the whole file in memory.
2686
 * Return malloc-ed file content, or NULL on error. The caller must free().
2687
 */
2688
char *json_fread(const char *file_name);
2689
2690
/*
2691
 * Update given JSON string `s,len` by changing the value at given `json_path`.
2692
 * The result is saved to `out`. If `json_fmt` == NULL, that deletes the key.
2693
 * If path is not present, missing keys are added. Array path without an
2694
 * index pushes a value to the end of an array.
2695
 * Return 1 if the string was changed, 0 otherwise.
2696
 *
2697
 * Example:  s is a JSON string { "a": 1, "b": [ 2 ] }
2698
 *   json_setf(s, len, out, ".a", "7");     // { "a": 7, "b": [ 2 ] }
2699
 *   json_setf(s, len, out, ".b", "7");     // { "a": 1, "b": 7 }
2700
 *   json_setf(s, len, out, ".b[]", "7");   // { "a": 1, "b": [ 2,7 ] }
2701
 *   json_setf(s, len, out, ".b", NULL);    // { "a": 1 }
2702
 */
2703
int json_setf(const char *s, int len, struct json_out *out,
2704
              const char *json_path, const char *json_fmt, ...);
2705
2706
int json_vsetf(const char *s, int len, struct json_out *out,
2707
               const char *json_path, const char *json_fmt, va_list ap);
2708
2709
/*
2710
 * Pretty-print JSON string `s,len` into `out`.
2711
 * Return number of processed bytes in `s`.
2712
 */
2713
int json_prettify(const char *s, int len, struct json_out *out);
2714
2715
/*
2716
 * Prettify JSON file `file_name`.
2717
 * Return number of processed bytes, or negative number of error.
2718
 * On error, file content is not modified.
2719
 */
2720
int json_prettify_file(const char *file_name);
2721
2722
/*
2723
 * Iterate over an object at given JSON `path`.
2724
 * On each iteration, fill the `key` and `val` tokens. It is OK to pass NULL
2725
 * for `key`, or `val`, in which case they won't be populated.
2726
 * Return an opaque value suitable for the next iteration, or NULL when done.
2727
 *
2728
 * Example:
2729
 *
2730
 * ```c
2731
 * void *h = NULL;
2732
 * struct json_token key, val;
2733
 * while ((h = json_next_key(s, len, h, ".foo", &key, &val)) != NULL) {
2734
 *   printf("[%.*s] -> [%.*s]\n", key.len, key.ptr, val.len, val.ptr);
2735
 * }
2736
 * ```
2737
 */
2738
void *json_next_key(const char *s, int len, void *handle, const char *path,
2739
                    struct json_token *key, struct json_token *val);
2740
2741
/*
2742
 * Iterate over an array at given JSON `path`.
2743
 * Similar to `json_next_key`, but fills array index `idx` instead of `key`.
2744
 */
2745
void *json_next_elem(const char *s, int len, void *handle, const char *path,
2746
                     int *idx, struct json_token *val);
2747
2748
#ifdef __cplusplus
2749
}
2750
#endif /* __cplusplus */
2751
2752
#endif /* CS_FROZEN_FROZEN_H_ */
2753
#ifdef MJS_MODULE_LINES
2754
#line 1 "mjs/src/ffi/ffi.h"
2755
#endif
2756
/*
2757
 * Copyright (c) 2016 Cesanta Software Limited
2758
 * All rights reserved
2759
 */
2760
2761
#ifndef MJS_FFI_FFI_H_
2762
#define MJS_FFI_FFI_H_
2763
2764
/* Amalgamated: #include "common/platform.h" */
2765
2766
#if defined(__cplusplus)
2767
extern "C" {
2768
#endif /* __cplusplus */
2769
2770
/*
2771
 * Maximum number of word-sized args to ffi-ed function. If at least one
2772
 * of the args is double, only 2 args are allowed.
2773
 */
2774
#define FFI_MAX_ARGS_CNT 6
2775
2776
typedef void(ffi_fn_t)(void);
2777
2778
typedef intptr_t ffi_word_t;
2779
2780
enum ffi_ctype {
2781
  FFI_CTYPE_WORD,
2782
  FFI_CTYPE_BOOL,
2783
  FFI_CTYPE_FLOAT,
2784
  FFI_CTYPE_DOUBLE,
2785
};
2786
2787
struct ffi_arg {
2788
  enum ffi_ctype ctype;
2789
  union {
2790
    uint64_t i;
2791
    double d;
2792
    float f;
2793
  } v;
2794
};
2795
2796
int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res,
2797
             struct ffi_arg *args);
2798
2799
void ffi_set_word(struct ffi_arg *arg, ffi_word_t v);
2800
void ffi_set_bool(struct ffi_arg *arg, bool v);
2801
void ffi_set_ptr(struct ffi_arg *arg, void *v);
2802
void ffi_set_double(struct ffi_arg *arg, double v);
2803
void ffi_set_float(struct ffi_arg *arg, float v);
2804
2805
#if defined(__cplusplus)
2806
}
2807
#endif /* __cplusplus */
2808
2809
#endif /* MJS_FFI_FFI_H_ */
2810
#ifdef MJS_MODULE_LINES
2811
#line 1 "mjs/src/mjs_internal.h"
2812
#endif
2813
/*
2814
 * Copyright (c) 2016 Cesanta Software Limited
2815
 * All rights reserved
2816
 */
2817
2818
#ifndef MJS_INTERNAL_H_
2819
#define MJS_INTERNAL_H_
2820
2821
#include <assert.h>
2822
#include <ctype.h>
2823
#include <math.h>
2824
#include <stdarg.h>
2825
#include <stdio.h>
2826
#include <string.h>
2827
2828
#ifndef FAST
2829
#define FAST
2830
#endif
2831
2832
#ifndef STATIC
2833
#define STATIC
2834
#endif
2835
2836
#ifndef ENDL
2837
#define ENDL "\n"
2838
#endif
2839
2840
#ifdef MJS_EXPOSE_PRIVATE
2841
#define MJS_PRIVATE
2842
#define MJS_EXTERN extern
2843
#else
2844
#define MJS_PRIVATE static
2845
#define MJS_EXTERN static
2846
#endif
2847
2848
#ifndef ARRAY_SIZE
2849
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
2850
#endif
2851
2852
#if !defined(WEAK)
2853
#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
2854
#define WEAK __attribute__((weak))
2855
#else
2856
#define WEAK
2857
#endif
2858
#endif
2859
2860
#ifndef CS_ENABLE_STDIO
2861
#define CS_ENABLE_STDIO 1
2862
#endif
2863
2864
/* Amalgamated: #include "common/cs_dbg.h" */
2865
/* Amalgamated: #include "common/cs_file.h" */
2866
/* Amalgamated: #include "common/mbuf.h" */
2867
2868
#if defined(_WIN32) && _MSC_VER < 1700
2869
typedef signed char int8_t;
2870
typedef unsigned char uint8_t;
2871
typedef int int32_t;
2872
typedef unsigned int uint32_t;
2873
typedef short int16_t;
2874
typedef unsigned short uint16_t;
2875
typedef __int64 int64_t;
2876
typedef unsigned long uintptr_t;
2877
#define STRX(x) #x
2878
#define STR(x) STRX(x)
2879
#define __func__ __FILE__ ":" STR(__LINE__)
2880
// #define snprintf _snprintf
2881
#define vsnprintf _vsnprintf
2882
#define isnan(x) _isnan(x)
2883
#define va_copy(x, y) (x) = (y)
2884
#define CS_DEFINE_DIRENT
2885
#include <windows.h>
2886
#else
2887
#if defined(__unix__) || defined(__APPLE__)
2888
#include <dlfcn.h>
2889
#endif
2890
#endif
2891
2892
/*
2893
 * Number of bytes reserved for the jump offset initially. The most practical
2894
 * value is 1, but for testing it's useful to set it to 0 and to some large
2895
 * value as well (like, 4), to make sure that the code behaves correctly under
2896
 * all circumstances.
2897
 */
2898
#ifndef MJS_INIT_OFFSET_SIZE
2899
#define MJS_INIT_OFFSET_SIZE 1
2900
#endif
2901
2902
#endif /* MJS_INTERNAL_H_ */
2903
#ifdef MJS_MODULE_LINES
2904
#line 1 "mjs/src/mjs_license.h"
2905
#endif
2906
/*
2907
 * Copyright (c) 2017 Cesanta Software Limited
2908
 * All rights reserved
2909
 *
2910
 * This software is dual-licensed: you can redistribute it and/or modify
2911
 * it under the terms of the GNU General Public License version 2 as
2912
 * published by the Free Software Foundation. For the terms of this
2913
 * license, see <http://www.gnu.org/licenses/>.
2914
 *
2915
 * You are free to use this software under the terms of the GNU General
2916
 * Public License, but WITHOUT ANY WARRANTY; without even the implied
2917
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2918
 * See the GNU General Public License for more details.
2919
 *
2920
 * Alternatively, you can license this software under a commercial
2921
 * license, as set out in <https://www.cesanta.com/license>.
2922
 */
2923
#ifdef MJS_MODULE_LINES
2924
#line 1 "mjs/src/mjs_features.h"
2925
#endif
2926
/*
2927
 * Copyright (c) 2017 Cesanta Software Limited
2928
 * All rights reserved
2929
 */
2930
2931
#ifndef MJS_FEATURES_H_
2932
#define MJS_FEATURES_H_
2933
2934
#if !defined(MJS_AGGRESSIVE_GC)
2935
#define MJS_AGGRESSIVE_GC 0
2936
#endif
2937
2938
#if !defined(MJS_MEMORY_STATS)
2939
#define MJS_MEMORY_STATS 0
2940
#endif
2941
2942
/*
2943
 * MJS_GENERATE_JSC: if enabled, and if mmapping is also enabled (CS_MMAP),
2944
 * then execution of any .js file will result in creation of a .jsc file with
2945
 * precompiled bcode, and this .jsc file will be mmapped, instead of keeping
2946
 * bcode in RAM.
2947
 *
2948
 * By default it's enabled (provided that CS_MMAP is defined)
2949
 */
2950
#if !defined(MJS_GENERATE_JSC)
2951
#if defined(CS_MMAP)
2952
#define MJS_GENERATE_JSC 1
2953
#else
2954
#define MJS_GENERATE_JSC 0
2955
#endif
2956
#endif
2957
2958
#endif /* MJS_FEATURES_H_ */
2959
#ifdef MJS_MODULE_LINES
2960
#line 1 "mjs/src/mjs_core_public.h"
2961
#endif
2962
/*
2963
 * Copyright (c) 2016 Cesanta Software Limited
2964
 * All rights reserved
2965
 */
2966
2967
#ifndef MJS_CORE_PUBLIC_H_
2968
#define MJS_CORE_PUBLIC_H_
2969
2970
#if !defined(_MSC_VER) || _MSC_VER >= 1700
2971
#include <stdint.h>
2972
#else
2973
typedef unsigned __int64 uint64_t;
2974
typedef int int32_t;
2975
typedef unsigned char uint8_t;
2976
#endif
2977
#include <stdio.h>
2978
#include <stddef.h>
2979
/* Amalgamated: #include "mjs/src/mjs_license.h" */
2980
/* Amalgamated: #include "mjs/src/mjs_features.h" */
2981
2982
#if defined(__cplusplus)
2983
extern "C" {
2984
#endif /* __cplusplus */
2985
2986
#define MJS_ENABLE_DEBUG 1
2987
2988
/*
2989
 *  Double-precision floating-point number, IEEE 754
2990
 *
2991
 *  64 bit (8 bytes) in total
2992
 *  1  bit sign
2993
 *  11 bits exponent
2994
 *  52 bits mantissa
2995
 *      7         6        5        4        3        2        1        0
2996
 *  seeeeeee|eeeemmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm
2997
 *
2998
 * If an exponent is all-1 and mantissa is all-0, then it is an INFINITY:
2999
 *  11111111|11110000|00000000|00000000|00000000|00000000|00000000|00000000
3000
 *
3001
 * If an exponent is all-1 and mantissa's MSB is 1, it is a quiet NaN:
3002
 *  11111111|11111000|00000000|00000000|00000000|00000000|00000000|00000000
3003
 *
3004
 *  MJS NaN-packing:
3005
 *    sign and exponent is 0xfff
3006
 *    4 bits specify type (tag), must be non-zero
3007
 *    48 bits specify value
3008
 *
3009
 *  11111111|1111tttt|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv
3010
 *   NaN marker |type|  48-bit placeholder for values: pointers, strings
3011
 *
3012
 * On 64-bit platforms, pointers are really 48 bit only, so they can fit,
3013
 * provided they are sign extended
3014
 */
3015
3016
typedef uint64_t mjs_val_t;
3017
3018
/* This if-0 is a dirty workaround to force etags to pick `struct mjs` */
3019
#if 0
3020
/* Opaque structure. MJS engine context. */
3021
struct mjs {
3022
  /* ... */
3023
};
3024
#endif
3025
3026
struct mjs;
3027
3028
typedef enum mjs_err {
3029
  MJS_OK,
3030
  MJS_SYNTAX_ERROR,
3031
  MJS_REFERENCE_ERROR,
3032
  MJS_TYPE_ERROR,
3033
  MJS_OUT_OF_MEMORY,
3034
  MJS_INTERNAL_ERROR,
3035
  MJS_NOT_IMPLEMENTED_ERROR,
3036
  MJS_FILE_READ_ERROR,
3037
  MJS_BAD_ARGS_ERROR,
3038
3039
  MJS_ERRS_CNT
3040
} mjs_err_t;
3041
struct mjs;
3042
3043
/* Create MJS instance */
3044
struct mjs *mjs_create();
3045
3046
struct mjs_create_opts {
3047
  /* use non-default bytecode definition file, testing-only */
3048
  const struct bf_code *code;
3049
};
3050
3051
/*
3052
 * Like `msj_create()`, but allows to customize initial MJS state, see `struct
3053
 * mjs_create_opts`.
3054
 */
3055
struct mjs *mjs_create_opt(struct mjs_create_opts opts);
3056
3057
/* Destroy MJS instance */
3058
void mjs_destroy(struct mjs *mjs);
3059
3060
mjs_val_t mjs_get_global(struct mjs *mjs);
3061
3062
/*
3063
 * Tells the GC about an MJS value variable/field owned by C code.
3064
 *
3065
 * The user's C code should own mjs_val_t variables if the value's lifetime
3066
 * crosses any invocation of `mjs_exec()` and friends, including `mjs_call()`.
3067
 *
3068
 * The registration of the variable prevents the GC from mistakenly treat the
3069
 * object as garbage.
3070
 *
3071
 * User code should also explicitly disown the variables with `mjs_disown()`
3072
 * once it goes out of scope or the structure containing the mjs_val_t field is
3073
 * freed.
3074
 *
3075
 * Consider the following examples:
3076
 *
3077
 * Correct (owning is not necessary):
3078
 * ```c
3079
 * mjs_val_t res;
3080
 * mjs_exec(mjs, "....some script", &res);
3081
 * // ... use res somehow
3082
 *
3083
 * mjs_val_t res;
3084
 * mjs_exec(mjs, "....some script2", &res);
3085
 * // ... use new res somehow
3086
 * ```
3087
 *
3088
 * WRONG:
3089
 * ```c
3090
 * mjs_val_t res1;
3091
 * mjs_exec(mjs, "....some script", &res1);
3092
 *
3093
 * mjs_val_t res2;
3094
 * mjs_exec(mjs, "....some script2", &res2);
3095
 *
3096
 * // ... use res1 (WRONG!) and res2
3097
 * ```
3098
 *
3099
 * The code above is wrong, because after the second invocation of
3100
 * `mjs_exec()`, the value of `res1` is invalidated.
3101
 *
3102
 * Correct (res1 is owned)
3103
 * ```c
3104
 * mjs_val_t res1 = MJS_UNDEFINED;
3105
 * mjs_own(mjs, &res1);
3106
 * mjs_exec(mjs, "....some script", &res1);
3107
 *
3108
 * mjs_val_t res2 = MJS_UNDEFINED;
3109
 * mjs_exec(mjs, "....some script2", &res2);
3110
 *
3111
 * // ... use res1 and res2
3112
 * mjs_disown(mjs, &res1);
3113
 * ```
3114
 *
3115
 * NOTE that we explicly initialized `res1` to a valid value before owning it
3116
 * (in this case, the value is `MJS_UNDEFINED`). Owning an uninitialized
3117
 * variable is an undefined behaviour.
3118
 *
3119
 * Of course, it's not an error to own a variable even if it's not mandatory:
3120
 * e.g. in the last example we could own both `res1` and `res2`. Probably it
3121
 * would help us in the future, when we refactor the code so that `res2` has to
3122
 * be owned, and we could forget to do that.
3123
 *
3124
 * Also, if the user code has some C function called from MJS, and in this C
3125
 * function some MJS value (`mjs_val_t`) needs to be stored somewhhere and to
3126
 * stay alive after the C function has returned, it also needs to be properly
3127
 * owned.
3128
 */
3129
void mjs_own(struct mjs *mjs, mjs_val_t *v);
3130
3131
/*
3132
 * Disowns the value previously owned by `mjs_own()`.
3133
 *
3134
 * Returns 1 if value is found, 0 otherwise.
3135
 */
3136
int mjs_disown(struct mjs *mjs, mjs_val_t *v);
3137
3138
mjs_err_t mjs_set_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt, ...);
3139
3140
/*
3141
 * If there is no error message already set, then it's equal to
3142
 * `mjs_set_errorf()`.
3143
 *
3144
 * Otherwise, an old message gets prepended with the new one, followed by a
3145
 * colon. (the previously set error code is kept)
3146
 */
3147
mjs_err_t mjs_prepend_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt,
3148
                             ...);
3149
3150
/*
3151
 * Print the last error details. If print_stack_trace is non-zero, also
3152
 * print stack trace. `msg` is the message which gets prepended to the actual
3153
 * error message, if it's NULL, then "MJS error" is used.
3154
 */
3155
void mjs_print_error(struct mjs *mjs, FILE *fp, const char *msg,
3156
                     int print_stack_trace);
3157
3158
/*
3159
 * return a string representation of an error.
3160
 * the error string might be overwritten by calls to `mjs_set_errorf`.
3161
 */
3162
const char *mjs_strerror(struct mjs *mjs, enum mjs_err err);
3163
3164
/*
3165
 * Sets whether *.jsc files are generated when *.js file is executed. By
3166
 * default it's 0.
3167
 *
3168
 * If either `MJS_GENERATE_JSC` or `CS_MMAP` is off, then this function has no
3169
 * effect.
3170
 */
3171
void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc);
3172
3173
/*
3174
 * When invoked from a cfunction, returns number of arguments passed to the
3175
 * current JS function call.
3176
 */
3177
int mjs_nargs(struct mjs *mjs);
3178
3179
/*
3180
 * When invoked from a cfunction, returns n-th argument to the current JS
3181
 * function call.
3182
 */
3183
mjs_val_t mjs_arg(struct mjs *mjs, int n);
3184
3185
/*
3186
 * Sets return value for the current JS function call.
3187
 */
3188
void mjs_return(struct mjs *mjs, mjs_val_t v);
3189
3190
#if defined(__cplusplus)
3191
}
3192
#endif /* __cplusplus */
3193
3194
#endif /* MJS_CORE_PUBLIC_H_ */
3195
#ifdef MJS_MODULE_LINES
3196
#line 1 "mjs/src/mjs_array_public.h"
3197
#endif
3198
/*
3199
 * Copyright (c) 2017 Cesanta Software Limited
3200
 * All rights reserved
3201
 */
3202
3203
/*
3204
 * === Arrays
3205
 */
3206
3207
#ifndef MJS_ARRAY_PUBLIC_H_
3208
#define MJS_ARRAY_PUBLIC_H_
3209
3210
/* Amalgamated: #include "mjs/src/mjs_core_public.h" */
3211
3212
#if defined(__cplusplus)
3213
extern "C" {
3214
#endif /* __cplusplus */
3215
3216
/* Make an empty array object */
3217
mjs_val_t mjs_mk_array(struct mjs *mjs);
3218
3219
/* Returns length on an array. If `arr` is not an array, 0 is returned. */
3220
unsigned long mjs_array_length(struct mjs *mjs, mjs_val_t arr);
3221
3222
/* Insert value `v` in array `arr` at the end of the array. */
3223
mjs_err_t mjs_array_push(struct mjs *mjs, mjs_val_t arr, mjs_val_t v);
3224
3225
/*
3226
 * Return array member at index `index`. If `index` is out of bounds, undefined
3227
 * is returned.
3228
 */
3229
mjs_val_t mjs_array_get(struct mjs *, mjs_val_t arr, unsigned long index);
3230
3231
/* Insert value `v` into `arr` at index `index`. */
3232
mjs_err_t mjs_array_set(struct mjs *mjs, mjs_val_t arr, unsigned long index,
3233
                        mjs_val_t v);
3234
3235
/* Returns true if the given value is an array */
3236
int mjs_is_array(mjs_val_t v);
3237
3238
/* Delete value in array `arr` at index `index`, if it exists. */
3239
void mjs_array_del(struct mjs *mjs, mjs_val_t arr, unsigned long index);
3240
3241
#if defined(__cplusplus)
3242
}
3243
#endif /* __cplusplus */
3244
3245
#endif /* MJS_ARRAY_PUBLIC_H_ */
3246
#ifdef MJS_MODULE_LINES
3247
#line 1 "mjs/src/mjs_array.h"
3248
#endif
3249
/*
3250
 * Copyright (c) 2014 Cesanta Software Limited
3251
 * All rights reserved
3252
 */
3253
3254
#ifndef MJS_ARRAY_H_
3255
#define MJS_ARRAY_H_
3256
3257
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
3258
/* Amalgamated: #include "mjs/src/mjs_array_public.h" */
3259
3260
#if defined(__cplusplus)
3261
extern "C" {
3262
#endif /* __cplusplus */
3263
3264
MJS_PRIVATE mjs_val_t
3265
mjs_array_get2(struct mjs *mjs, mjs_val_t arr, unsigned long index, int *has);
3266
3267
MJS_PRIVATE void mjs_array_splice(struct mjs *mjs);
3268
3269
MJS_PRIVATE void mjs_array_push_internal(struct mjs *mjs);
3270
3271
#if defined(__cplusplus)
3272
}
3273
#endif /* __cplusplus */
3274
3275
#endif /* MJS_ARRAY_H_ */
3276
#ifdef MJS_MODULE_LINES
3277
#line 1 "mjs/src/mjs_ffi_public.h"
3278
#endif
3279
/*
3280
 * Copyright (c) 2016 Cesanta Software Limited
3281
 * All rights reserved
3282
 */
3283
3284
#ifndef MJS_FFI_PUBLIC_H_
3285
#define MJS_FFI_PUBLIC_H_
3286
3287
/* Amalgamated: #include "mjs/src/mjs_core_public.h" */
3288
3289
#if defined(__cplusplus)
3290
extern "C" {
3291
#endif /* __cplusplus */
3292
3293
enum mjs_ffi_ctype {
3294
  MJS_FFI_CTYPE_NONE,
3295
  MJS_FFI_CTYPE_USERDATA,
3296
  MJS_FFI_CTYPE_CALLBACK,
3297
  MJS_FFI_CTYPE_INT,
3298
  MJS_FFI_CTYPE_BOOL,
3299
  MJS_FFI_CTYPE_DOUBLE,
3300
  MJS_FFI_CTYPE_FLOAT,
3301
  MJS_FFI_CTYPE_CHAR_PTR,
3302
  MJS_FFI_CTYPE_VOID_PTR,
3303
  MJS_FFI_CTYPE_STRUCT_MG_STR_PTR,
3304
  MJS_FFI_CTYPE_STRUCT_MG_STR,
3305
  MJS_FFI_CTYPE_INVALID,
3306
};
3307
3308
typedef void *(mjs_ffi_resolver_t)(void *handle, const char *symbol);
3309
3310
void mjs_set_ffi_resolver(struct mjs *mjs, mjs_ffi_resolver_t *dlsym);
3311
3312
#if defined(__cplusplus)
3313
}
3314
#endif /* __cplusplus */
3315
3316
#endif /* MJS_FFI_PUBLIC_H_ */
3317
#ifdef MJS_MODULE_LINES
3318
#line 1 "mjs/src/mjs_ffi.h"
3319
#endif
3320
/*
3321
 * Copyright (c) 2017 Cesanta Software Limited
3322
 * All rights reserved
3323
 */
3324
3325
#ifndef MJS_FFI_H_
3326
#define MJS_FFI_H_
3327
3328
/* Amalgamated: #include "mjs/src/ffi/ffi.h" */
3329
/* Amalgamated: #include "mjs/src/mjs_ffi_public.h" */
3330
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
3331
3332
#if defined(__cplusplus)
3333
extern "C" {
3334
#endif /* __cplusplus */
3335
3336
mjs_ffi_resolver_t dlsym;
3337
3338
#define MJS_CB_ARGS_MAX_CNT 6
3339
#define MJS_CB_SIGNATURE_MAX_SIZE (MJS_CB_ARGS_MAX_CNT + 1 /* return type */)
3340
3341
typedef uint8_t mjs_ffi_ctype_t;
3342
3343
enum ffi_sig_type {
3344
  FFI_SIG_FUNC,
3345
  FFI_SIG_CALLBACK,
3346
};
3347
3348
/*
3349
 * Parsed FFI signature
3350
 */
3351
struct mjs_ffi_sig {
3352
  /*
3353
   * Callback signature, corresponds to the arg of type MJS_FFI_CTYPE_CALLBACK
3354
   * TODO(dfrank): probably we'll need to support multiple callback/userdata
3355
   * pairs
3356
   *
3357
   * NOTE(dfrank): instances of this structure are grouped into GC arenas and
3358
   * managed by GC, and for the GC mark to work, the first element should be
3359
   * a pointer (so that the two LSBs are not used).
3360
   */
3361
  struct mjs_ffi_sig *cb_sig;
3362
3363
  /*
3364
   * The first item is the return value type (for `void`, `MJS_FFI_CTYPE_NONE`
3365
   * is used); the rest are arguments. If some argument is
3366
   * `MJS_FFI_CTYPE_NONE`, it means that there are no more arguments.
3367
   */
3368
  mjs_ffi_ctype_t val_types[MJS_CB_SIGNATURE_MAX_SIZE];
3369
3370
  /*
3371
   * Function to call. If `is_callback` is not set, then it's the function
3372
   * obtained by dlsym; otherwise it's a pointer to the appropriate callback
3373
   * implementation.
3374
   */
3375
  ffi_fn_t *fn;
3376
3377
  /* Number of arguments in the signature */
3378
  int8_t args_cnt;
3379
3380
  /*
3381
   * If set, then the signature represents the callback (as opposed to a normal
3382
   * function), and `fn` points to the suitable callback implementation.
3383
   */
3384
  unsigned is_callback : 1;
3385
  unsigned is_valid : 1;
3386
};
3387
typedef struct mjs_ffi_sig mjs_ffi_sig_t;
3388
3389
/* Initialize new FFI signature */
3390
MJS_PRIVATE void mjs_ffi_sig_init(mjs_ffi_sig_t *sig);
3391
/* Copy existing FFI signature */
3392
MJS_PRIVATE void mjs_ffi_sig_copy(mjs_ffi_sig_t *to, const mjs_ffi_sig_t *from);
3393
/* Free FFI signature. NOTE: the pointer `sig` itself is not freed */
3394
MJS_PRIVATE void mjs_ffi_sig_free(mjs_ffi_sig_t *sig);
3395
3396
/*
3397
 * Creates a new FFI signature from the GC arena, and return mjs_val_t which
3398
 * wraps it.
3399
 */
3400
MJS_PRIVATE mjs_val_t mjs_mk_ffi_sig(struct mjs *mjs);
3401
3402
/*
3403
 * Checks whether the given value is a FFI signature.
3404
 */
3405
MJS_PRIVATE int mjs_is_ffi_sig(mjs_val_t v);
3406
3407
/*
3408
 * Wraps FFI signature structure into mjs_val_t value.
3409
 */
3410
MJS_PRIVATE mjs_val_t mjs_ffi_sig_to_value(struct mjs_ffi_sig *psig);
3411
3412
/*
3413
 * Extracts a pointer to the FFI signature struct from the mjs_val_t value.
3414
 */
3415
MJS_PRIVATE struct mjs_ffi_sig *mjs_get_ffi_sig_struct(mjs_val_t v);
3416
3417
/*
3418
 * A wrapper for mjs_ffi_sig_free() suitable to use as a GC cell destructor.
3419
 */
3420
MJS_PRIVATE void mjs_ffi_sig_destructor(struct mjs *mjs, void *psig);
3421
3422
MJS_PRIVATE int mjs_ffi_sig_set_val_type(mjs_ffi_sig_t *sig, int idx,
3423
                                         mjs_ffi_ctype_t type);
3424
MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig,
3425
                                     enum ffi_sig_type sig_type);
3426
MJS_PRIVATE int mjs_ffi_is_regular_word(mjs_ffi_ctype_t type);
3427
MJS_PRIVATE int mjs_ffi_is_regular_word_or_void(mjs_ffi_ctype_t type);
3428
3429
struct mjs_ffi_cb_args {
3430
  struct mjs_ffi_cb_args *next;
3431
  struct mjs *mjs;
3432
  mjs_ffi_sig_t sig;
3433
  mjs_val_t func;
3434
  mjs_val_t userdata;
3435
};
3436
typedef struct mjs_ffi_cb_args ffi_cb_args_t;
3437
3438
/*
3439
 * cfunction:
3440
 * Parses the FFI signature string and returns a value wrapping mjs_ffi_sig_t.
3441
 */
3442
MJS_PRIVATE mjs_err_t mjs_ffi_call(struct mjs *mjs);
3443
3444
/*
3445
 * cfunction:
3446
 * Performs the FFI signature call.
3447
 */
3448
MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs);
3449
3450
MJS_PRIVATE void mjs_ffi_cb_free(struct mjs *);
3451
MJS_PRIVATE void mjs_ffi_args_free_list(struct mjs *mjs);
3452
3453
#if defined(__cplusplus)
3454
}
3455
#endif /* __cplusplus */
3456
3457
#endif /* MJS_FFI_H_ */
3458
#ifdef MJS_MODULE_LINES
3459
#line 1 "mjs/src/mjs_mm.h"
3460
#endif
3461
/*
3462
 * Copyright (c) 2014-2016 Cesanta Software Limited
3463
 * All rights reserved
3464
 */
3465
3466
#ifndef MJS_MM_H_
3467
#define MJS_MM_H_
3468
3469
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
3470
3471
#if defined(__cplusplus)
3472
extern "C" {
3473
#endif /* __cplusplus */
3474
3475
struct mjs;
3476
3477
typedef void (*gc_cell_destructor_t)(struct mjs *mjs, void *);
3478
3479
struct gc_block {
3480
  struct gc_block *next;
3481
  struct gc_cell *base;
3482
  size_t size;
3483
};
3484
3485
struct gc_arena {
3486
  struct gc_block *blocks;
3487
  size_t size_increment;
3488
  struct gc_cell *free; /* head of free list */
3489
  size_t cell_size;
3490
3491
#if MJS_MEMORY_STATS
3492
  unsigned long allocations; /* cumulative counter of allocations */
3493
  unsigned long garbage;     /* cumulative counter of garbage */
3494
  unsigned long alive;       /* number of living cells */
3495
#endif
3496
3497
  gc_cell_destructor_t destructor;
3498
};
3499
3500
#if defined(__cplusplus)
3501
}
3502
#endif /* __cplusplus */
3503
3504
#endif /* MJS_MM_H_ */
3505
#ifdef MJS_MODULE_LINES
3506
#line 1 "mjs/src/mjs_gc.h"
3507
#endif
3508
/*
3509
 * Copyright (c) 2014 Cesanta Software Limited
3510
 * All rights reserved
3511
 */
3512
3513
#ifndef MJS_GC_H_
3514
#define MJS_GC_H_
3515
3516
/* Amalgamated: #include "mjs/src/mjs_core.h" */
3517
/* Amalgamated: #include "mjs/src/mjs_mm.h" */
3518
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
3519
3520
#if defined(__cplusplus)
3521
extern "C" {
3522
#endif /* __cplusplus */
3523
3524
/*
3525
 * performs arithmetics on gc_cell pointers as if they were arena->cell_size
3526
 * bytes wide
3527
 */
3528
#define GC_CELL_OP(arena, cell, op, arg) \
3529
  ((struct gc_cell *) (((char *) (cell)) op((arg) * (arena)->cell_size)))
3530
3531
struct gc_cell {
3532
  union {
3533
    struct gc_cell *link;
3534
    uintptr_t word;
3535
  } head;
3536
};
3537
3538
/*
3539
 * Perform garbage collection.
3540
 * Pass true to full in order to reclaim unused heap back to the OS.
3541
 */
3542
void mjs_gc(struct mjs *mjs, int full);
3543
3544
MJS_PRIVATE int gc_strings_is_gc_needed(struct mjs *mjs);
3545
3546
/* perform gc if not inhibited */
3547
MJS_PRIVATE int maybe_gc(struct mjs *mjs);
3548
3549
MJS_PRIVATE struct mjs_object *new_object(struct mjs *);
3550
MJS_PRIVATE struct mjs_property *new_property(struct mjs *);
3551
MJS_PRIVATE struct mjs_ffi_sig *new_ffi_sig(struct mjs *mjs);
3552
3553
MJS_PRIVATE void gc_mark(struct mjs *mjs, mjs_val_t *val);
3554
3555
MJS_PRIVATE void gc_arena_init(struct gc_arena *, size_t, size_t, size_t);
3556
MJS_PRIVATE void gc_arena_destroy(struct mjs *, struct gc_arena *a);
3557
MJS_PRIVATE void gc_sweep(struct mjs *, struct gc_arena *, size_t);
3558
MJS_PRIVATE void *gc_alloc_cell(struct mjs *, struct gc_arena *);
3559
3560
MJS_PRIVATE uint64_t gc_string_mjs_val_to_offset(mjs_val_t v);
3561
3562
/* return 0 if v is an object/function with a bad pointer */
3563
MJS_PRIVATE int gc_check_val(struct mjs *mjs, mjs_val_t v);
3564
3565
/* checks whether a pointer is within the ranges of an arena */
3566
MJS_PRIVATE int gc_check_ptr(const struct gc_arena *a, const void *p);
3567
3568
#if defined(__cplusplus)
3569
}
3570
#endif /* __cplusplus */
3571
3572
#endif /* MJS_GC_H_ */
3573
#ifdef MJS_MODULE_LINES
3574
#line 1 "mjs/src/mjs_core.h"
3575
#endif
3576
/*
3577
 * Copyright (c) 2017 Cesanta Software Limited
3578
 * All rights reserved
3579
 */
3580
3581
#ifndef MJS_CORE_H
3582
#define MJS_CORE_H
3583
3584
/* Amalgamated: #include "mjs/src/mjs_ffi.h" */
3585
/* Amalgamated: #include "mjs/src/mjs_gc.h" */
3586
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
3587
3588
#if defined(__cplusplus)
3589
extern "C" {
3590
#endif /* __cplusplus */
3591
3592
#define JUMP_INSTRUCTION_SIZE 2
3593
3594
enum mjs_type {
3595
  /* Primitive types */
3596
  MJS_TYPE_UNDEFINED,
3597
  MJS_TYPE_NULL,
3598
  MJS_TYPE_BOOLEAN,
3599
  MJS_TYPE_NUMBER,
3600
  MJS_TYPE_STRING,
3601
  MJS_TYPE_FOREIGN,
3602
3603
  /* Different classes of Object type */
3604
  MJS_TYPE_OBJECT_GENERIC,
3605
  MJS_TYPE_OBJECT_ARRAY,
3606
  MJS_TYPE_OBJECT_FUNCTION,
3607
  /*
3608
   * TODO(dfrank): if we support prototypes, need to add items for them here
3609
   */
3610
3611
  MJS_TYPES_CNT
3612
};
3613
3614
enum mjs_call_stack_frame_item {
3615
  CALL_STACK_FRAME_ITEM_RETVAL_STACK_IDX, /* TOS */
3616
  CALL_STACK_FRAME_ITEM_LOOP_ADDR_IDX,
3617
  CALL_STACK_FRAME_ITEM_SCOPE_IDX,
3618
  CALL_STACK_FRAME_ITEM_RETURN_ADDR,
3619
  CALL_STACK_FRAME_ITEM_THIS,
3620
3621
  CALL_STACK_FRAME_ITEMS_CNT
3622
};
3623
3624
/*
3625
 * A tag is made of the sign bit and the 4 lower order bits of byte 6.
3626
 * So in total we have 32 possible tags.
3627
 *
3628
 * Tag (1,0) however cannot hold a zero payload otherwise it's interpreted as an
3629
 * INFINITY; for simplicity we're just not going to use that combination.
3630
 */
3631
#define MAKE_TAG(s, t) \
3632
  ((uint64_t)(s) << 63 | (uint64_t) 0x7ff0 << 48 | (uint64_t)(t) << 48)
3633
3634
#define MJS_TAG_OBJECT MAKE_TAG(1, 1)
3635
#define MJS_TAG_FOREIGN MAKE_TAG(1, 2)
3636
#define MJS_TAG_UNDEFINED MAKE_TAG(1, 3)
3637
#define MJS_TAG_BOOLEAN MAKE_TAG(1, 4)
3638
#define MJS_TAG_NAN MAKE_TAG(1, 5)
3639
#define MJS_TAG_STRING_I MAKE_TAG(1, 6)  /* Inlined string len < 5 */
3640
#define MJS_TAG_STRING_5 MAKE_TAG(1, 7)  /* Inlined string len 5 */
3641
#define MJS_TAG_STRING_O MAKE_TAG(1, 8)  /* Owned string */
3642
#define MJS_TAG_STRING_F MAKE_TAG(1, 9)  /* Foreign string */
3643
#define MJS_TAG_STRING_C MAKE_TAG(1, 10) /* String chunk */
3644
#define MJS_TAG_STRING_D MAKE_TAG(1, 11) /* Dictionary string  */
3645
#define MJS_TAG_ARRAY MAKE_TAG(1, 12)
3646
#define MJS_TAG_FUNCTION MAKE_TAG(1, 13)
3647
#define MJS_TAG_FUNCTION_FFI MAKE_TAG(1, 14)
3648
#define MJS_TAG_NULL MAKE_TAG(1, 15)
3649
3650
#define MJS_TAG_MASK MAKE_TAG(1, 15)
3651
3652
struct mjs_vals {
3653
  /* Current `this` value  */
3654
  mjs_val_t this_obj;
3655
  mjs_val_t dataview_proto;
3656
3657
  /*
3658
   * The object against which the last `OP_GET` was invoked. Needed for
3659
   * "method invocation pattern".
3660
   */
3661
  mjs_val_t last_getprop_obj;
3662
};
3663
3664
struct mjs_bcode_part {
3665
  /* Global index of the bcode part */
3666
  size_t start_idx;
3667
3668
  /* Actual bcode data */
3669
  struct {
3670
    const char *p; /* Memory chunk pointer */
3671
    size_t len;    /* Memory chunk length */
3672
  } data;
3673
3674
  /*
3675
   * Result of evaluation (not parsing: if there is an error during parsing,
3676
   * the bcode is not even committed). It is used to determine whether we
3677
   * need to evaluate the file: if file was already evaluated, and the result
3678
   * was MJS_OK, then we won't evaluate it again. Otherwise, we will.
3679
   */
3680
  mjs_err_t exec_res : 4;
3681
3682
  /* If set, bcode data does not need to be freed */
3683
  unsigned in_rom : 1;
3684
};
3685
3686
struct mjs {
3687
  struct mbuf bcode_gen;
3688
  struct mbuf bcode_parts;
3689
  size_t bcode_len;
3690
  struct mbuf stack;
3691
  struct mbuf call_stack;
3692
  struct mbuf arg_stack;
3693
  struct mbuf scopes;          /* Scope objects */
3694
  struct mbuf loop_addresses;  /* Addresses for breaks & continues */
3695
  struct mbuf owned_strings;   /* Sequence of (varint len, char data[]) */
3696
  struct mbuf foreign_strings; /* Sequence of (varint len, char *data) */
3697
  struct mbuf owned_values;
3698
  struct mbuf json_visited_stack;
3699
  struct mjs_vals vals;
3700
  char *error_msg;
3701
  char *stack_trace;
3702
  enum mjs_err error;
3703
  mjs_ffi_resolver_t *dlsym;  /* Symbol resolver function for FFI */
3704
  ffi_cb_args_t *ffi_cb_args; /* List of FFI args descriptors */
3705
  size_t cur_bcode_offset;
3706
3707
  struct gc_arena object_arena;
3708
  struct gc_arena property_arena;
3709
  struct gc_arena ffi_sig_arena;
3710
3711
  unsigned inhibit_gc : 1;
3712
  unsigned need_gc : 1;
3713
  unsigned generate_jsc : 1;
3714
};
3715
3716
/*
3717
 * Bcode header: type of the items, and item numbers.
3718
 */
3719
typedef uint32_t mjs_header_item_t;
3720
enum mjs_header_items {
3721
  MJS_HDR_ITEM_TOTAL_SIZE,   /* Total size of the bcode (not counting the
3722
                                OP_BCODE_HEADER byte) */
3723
  MJS_HDR_ITEM_BCODE_OFFSET, /* Offset to the start of the actual bcode (not
3724
                                counting the OP_BCODE_HEADER byte) */
3725
  MJS_HDR_ITEM_MAP_OFFSET,   /* Offset to the start of offset-to-line_no mapping
3726
                                k*/
3727
3728
  MJS_HDR_ITEMS_CNT
3729
};
3730
3731
MJS_PRIVATE size_t mjs_get_func_addr(mjs_val_t v);
3732
3733
MJS_PRIVATE int mjs_getretvalpos(struct mjs *mjs);
3734
3735
MJS_PRIVATE enum mjs_type mjs_get_type(mjs_val_t v);
3736
3737
/*
3738
 * Prints stack trace starting from the given bcode offset; other offsets
3739
 * (if any) will be fetched from the call_stack.
3740
 */
3741
MJS_PRIVATE void mjs_gen_stack_trace(struct mjs *mjs, size_t offset);
3742
3743
MJS_PRIVATE mjs_val_t vtop(struct mbuf *m);
3744
MJS_PRIVATE size_t mjs_stack_size(const struct mbuf *m);
3745
MJS_PRIVATE mjs_val_t *vptr(struct mbuf *m, int idx);
3746
MJS_PRIVATE void push_mjs_val(struct mbuf *m, mjs_val_t v);
3747
MJS_PRIVATE mjs_val_t mjs_pop_val(struct mbuf *m);
3748
MJS_PRIVATE mjs_val_t mjs_pop(struct mjs *mjs);
3749
MJS_PRIVATE void mjs_push(struct mjs *mjs, mjs_val_t v);
3750
MJS_PRIVATE void mjs_die(struct mjs *mjs);
3751
3752
#if defined(__cplusplus)
3753
}
3754
#endif /* __cplusplus */
3755
3756
#endif /* MJS_CORE_H */
3757
#ifdef MJS_MODULE_LINES
3758
#line 1 "mjs/src/mjs_conversion.h"
3759
#endif
3760
/*
3761
 * Copyright (c) 2016 Cesanta Software Limited
3762
 * All rights reserved
3763
 */
3764
3765
#ifndef MJS_CONVERSION_H_
3766
#define MJS_CONVERSION_H_
3767
3768
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
3769
/* Amalgamated: #include "mjs/src/mjs_core.h" */
3770
3771
#if defined(__cplusplus)
3772
extern "C" {
3773
#endif /* __cplusplus */
3774
3775
/*
3776
 * Tries to convert `mjs_val_t` to a string, returns MJS_OK if successful.
3777
 * String is returned as a pair of pointers: `char **p, size_t *sizep`.
3778
 *
3779
 * Caller must also provide a non-null `need_free`, and if it is non-zero,
3780
 * then the string `*p` should be freed by the caller.
3781
 *
3782
 * MJS does not support `toString()` and `valueOf()`, so, passing an object
3783
 * always results in `MJS_TYPE_ERROR`.
3784
 */
3785
MJS_PRIVATE mjs_err_t mjs_to_string(struct mjs *mjs, mjs_val_t *v, char **p,
3786
                                    size_t *sizep, int *need_free);
3787
3788
/*
3789
 * Converts value to boolean as in the expression `if (v)`.
3790
 */
3791
MJS_PRIVATE mjs_val_t mjs_to_boolean_v(struct mjs *mjs, mjs_val_t v);
3792
3793
MJS_PRIVATE int mjs_is_truthy(struct mjs *mjs, mjs_val_t v);
3794
3795
#if defined(__cplusplus)
3796
}
3797
#endif /* __cplusplus */
3798
3799
#endif /* MJS_CONVERSION_H_ */
3800
#ifdef MJS_MODULE_LINES
3801
#line 1 "mjs/src/mjs_object_public.h"
3802
#endif
3803
/*
3804
 * Copyright (c) 2016 Cesanta Software Limited
3805
 * All rights reserved
3806
 */
3807
3808
#ifndef MJS_OBJECT_PUBLIC_H_
3809
#define MJS_OBJECT_PUBLIC_H_
3810
3811
#include <stddef.h>
3812
/* Amalgamated: #include "mjs/src/mjs_core_public.h" */
3813
/* Amalgamated: #include "mjs/src/mjs_ffi_public.h" */
3814
3815
#if defined(__cplusplus)
3816
extern "C" {
3817
#endif /* __cplusplus */
3818
3819
/*
3820
 * Returns true if the given value is an object or array.
3821
 */
3822
int mjs_is_object(mjs_val_t v);
3823
3824
/* Make an empty object */
3825
mjs_val_t mjs_mk_object(struct mjs *mjs);
3826
3827
/* C structure layout descriptor - needed by mjs_struct_to_obj */
3828
struct mjs_c_struct_member {
3829
  const char *name;
3830
  size_t offset;
3831
  enum mjs_ffi_ctype type;
3832
};
3833
3834
/* Create flat JS object from a C memory descriptor */
3835
mjs_val_t mjs_struct_to_obj(struct mjs *mjs, const void *base,
3836
                            const struct mjs_c_struct_member *members);
3837
3838
/*
3839
 * Lookup property `name` in object `obj`. If `obj` holds no such property,
3840
 * an `undefined` value is returned.
3841
 *
3842
 * If `name_len` is ~0, `name` is assumed to be NUL-terminated and
3843
 * `strlen(name)` is used.
3844
 */
3845
mjs_val_t mjs_get(struct mjs *mjs, mjs_val_t obj, const char *name,
3846
                  size_t name_len);
3847
3848
/*
3849
 * Like mjs_get but with a JS string.
3850
 */
3851
mjs_val_t mjs_get_v(struct mjs *mjs, mjs_val_t obj, mjs_val_t name);
3852
3853
/*
3854
 * Like mjs_get_v but lookup the prototype chain.
3855
 */
3856
mjs_val_t mjs_get_v_proto(struct mjs *mjs, mjs_val_t obj, mjs_val_t key);
3857
3858
/*
3859
 * Set object property. Behaves just like JavaScript assignment.
3860
 */
3861
mjs_err_t mjs_set(struct mjs *mjs, mjs_val_t obj, const char *name, size_t len,
3862
                  mjs_val_t val);
3863
3864
/*
3865
 * Like mjs_set but the name is already a JS string.
3866
 */
3867
mjs_err_t mjs_set_v(struct mjs *mjs, mjs_val_t obj, mjs_val_t name,
3868
                    mjs_val_t val);
3869
3870
/*
3871
 * Delete own property `name` of the object `obj`. Does not follow the
3872
 * prototype chain.
3873
 *
3874
 * If `name_len` is ~0, `name` is assumed to be NUL-terminated and
3875
 * `strlen(name)` is used.
3876
 *
3877
 * Returns 0 on success, -1 on error.
3878
 */
3879
int mjs_del(struct mjs *mjs, mjs_val_t obj, const char *name, size_t len);
3880
3881
/*
3882
 * Iterate over `obj` properties.
3883
 * First call should set `iterator` to MJS_UNDEFINED.
3884
 * Return object's key (a string), or MJS_UNDEFINED when no more keys left.
3885
 * Do not mutate the object during iteration.
3886
 *
3887
 * Example:
3888
 *   mjs_val_t key, iter = MJS_UNDEFINED;
3889
 *   while ((key = mjs_next(mjs, obj, &iter)) != MJS_UNDEFINED) {
3890
 *     // Do something with the obj/key ...
3891
 *   }
3892
 */
3893
mjs_val_t mjs_next(struct mjs *mjs, mjs_val_t obj, mjs_val_t *iterator);
3894
3895
#if defined(__cplusplus)
3896
}
3897
#endif /* __cplusplus */
3898
3899
#endif /* MJS_OBJECT_PUBLIC_H_ */
3900
#ifdef MJS_MODULE_LINES
3901
#line 1 "mjs/src/mjs_object.h"
3902
#endif
3903
/*
3904
 * Copyright (c) 2016 Cesanta Software Limited
3905
 * All rights reserved
3906
 */
3907
3908
#ifndef MJS_OBJECT_H_
3909
#define MJS_OBJECT_H_
3910
3911
/* Amalgamated: #include "mjs/src/mjs_object_public.h" */
3912
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
3913
3914
#if defined(__cplusplus)
3915
extern "C" {
3916
#endif /* __cplusplus */
3917
3918
struct mjs;
3919
3920
struct mjs_property {
3921
  struct mjs_property *next; /* Linkage in struct mjs_object::properties */
3922
  mjs_val_t name;            /* Property name (a string) */
3923
  mjs_val_t value;           /* Property value */
3924
};
3925
3926
struct mjs_object {
3927
  struct mjs_property *properties;
3928
};
3929
3930
MJS_PRIVATE struct mjs_object *get_object_struct(mjs_val_t v);
3931
MJS_PRIVATE struct mjs_property *mjs_get_own_property(struct mjs *mjs,
3932
                                                      mjs_val_t obj,
3933
                                                      const char *name,
3934
                                                      size_t len);
3935
3936
MJS_PRIVATE struct mjs_property *mjs_get_own_property_v(struct mjs *mjs,
3937
                                                        mjs_val_t obj,
3938
                                                        mjs_val_t key);
3939
3940
/*
3941
 * A worker function for `mjs_set()` and `mjs_set_v()`: it takes name as both
3942
 * ptr+len and mjs_val_t. If `name` pointer is not NULL, it takes precedence
3943
 * over `name_v`.
3944
 */
3945
MJS_PRIVATE mjs_err_t mjs_set_internal(struct mjs *mjs, mjs_val_t obj,
3946
                                       mjs_val_t name_v, char *name,
3947
                                       size_t name_len, mjs_val_t val);
3948
3949
/*
3950
 * Implementation of `Object.create(proto)`
3951
 */
3952
MJS_PRIVATE void mjs_op_create_object(struct mjs *mjs);
3953
3954
#define MJS_PROTO_PROP_NAME "__p" /* Make it < 5 chars */
3955
3956
#if defined(__cplusplus)
3957
}
3958
#endif /* __cplusplus */
3959
3960
#endif /* MJS_OBJECT_H_ */
3961
#ifdef MJS_MODULE_LINES
3962
#line 1 "mjs/src/mjs_primitive_public.h"
3963
#endif
3964
/*
3965
 * Copyright (c) 2016 Cesanta Software Limited
3966
 * All rights reserved
3967
 */
3968
3969
#ifndef MJS_PRIMITIVE_PUBLIC_H_
3970
#define MJS_PRIMITIVE_PUBLIC_H_
3971
3972
/* Amalgamated: #include "mjs/src/mjs_core_public.h" */
3973
3974
#if defined(__cplusplus)
3975
extern "C" {
3976
#endif /* __cplusplus */
3977
3978
/* JavaScript `null` value */
3979
#define MJS_NULL MJS_TAG_NULL
3980
3981
/* JavaScript `undefined` value */
3982
#define MJS_UNDEFINED MJS_TAG_UNDEFINED
3983
3984
/* Function pointer type used in `mjs_mk_foreign_func`. */
3985
typedef void (*mjs_func_ptr_t)(void);
3986
3987
/*
3988
 * Make `null` primitive value.
3989
 *
3990
 * NOTE: this function is deprecated and will be removed in future releases.
3991
 * Use `MJS_NULL` instead.
3992
 */
3993
mjs_val_t mjs_mk_null(void);
3994
3995
/* Returns true if given value is a primitive `null` value */
3996
int mjs_is_null(mjs_val_t v);
3997
3998
/*
3999
 * Make `undefined` primitive value.
4000
 *
4001
 * NOTE: this function is deprecated and will be removed in future releases.
4002
 * Use `MJS_UNDEFINED` instead.
4003
 */
4004
mjs_val_t mjs_mk_undefined(void);
4005
4006
/* Returns true if given value is a primitive `undefined` value */
4007
int mjs_is_undefined(mjs_val_t v);
4008
4009
/* Make numeric primitive value */
4010
mjs_val_t mjs_mk_number(struct mjs *mjs, double num);
4011
4012
/*
4013
 * Returns number value stored in `mjs_val_t` as `double`.
4014
 *
4015
 * Returns NaN for non-numbers.
4016
 */
4017
double mjs_get_double(struct mjs *mjs, mjs_val_t v);
4018
4019
/*
4020
 * Returns number value stored in `mjs_val_t` as `int`. If the number value is
4021
 * not an integer, the fraction part will be discarded.
4022
 *
4023
 * If the given value is a non-number, or NaN, the result is undefined.
4024
 */
4025
int mjs_get_int(struct mjs *mjs, mjs_val_t v);
4026
4027
/*
4028
 * Like mjs_get_int but ensures that the returned type
4029
 * is a 32-bit signed integer.
4030
 */
4031
int32_t mjs_get_int32(struct mjs *mjs, mjs_val_t v);
4032
4033
/* Returns true if given value is a primitive number value */
4034
int mjs_is_number(mjs_val_t v);
4035
4036
/*
4037
 * Make JavaScript value that holds C/C++ `void *` pointer.
4038
 *
4039
 * A foreign value is completely opaque and JS code cannot do anything useful
4040
 * with it except holding it in properties and passing it around.
4041
 * It behaves like a sealed object with no properties.
4042
 *
4043
 * NOTE:
4044
 * Only valid pointers (as defined by each supported architecture) will fully
4045
 * preserved. In particular, all supported 64-bit architectures (x86_64, ARM-64)
4046
 * actually define a 48-bit virtual address space.
4047
 * Foreign values will be sign-extended as required, i.e creating a foreign
4048
 * value of something like `(void *) -1` will work as expected. This is
4049
 * important because in some 64-bit OSs (e.g. Solaris) the user stack grows
4050
 * downwards from the end of the address space.
4051
 *
4052
 * If you need to store exactly sizeof(void*) bytes of raw data where
4053
 * `sizeof(void*)` >= 8, please use byte arrays instead.
4054
 */
4055
mjs_val_t mjs_mk_foreign(struct mjs *mjs, void *ptr);
4056
4057
/*
4058
 * Make JavaScript value that holds C/C++ function pointer, similarly to
4059
 * `mjs_mk_foreign`.
4060
 */
4061
mjs_val_t mjs_mk_foreign_func(struct mjs *mjs, mjs_func_ptr_t fn);
4062
4063
/*
4064
 * Returns `void *` pointer stored in `mjs_val_t`.
4065
 *
4066
 * Returns NULL if the value is not a foreign pointer.
4067
 */
4068
void *mjs_get_ptr(struct mjs *mjs, mjs_val_t v);
4069
4070
/* Returns true if given value holds `void *` pointer */
4071
int mjs_is_foreign(mjs_val_t v);
4072
4073
mjs_val_t mjs_mk_boolean(struct mjs *mjs, int v);
4074
int mjs_get_bool(struct mjs *mjs, mjs_val_t v);
4075
int mjs_is_boolean(mjs_val_t v);
4076
4077
mjs_val_t mjs_mk_function(struct mjs *mjs, size_t off);
4078
int mjs_is_function(mjs_val_t v);
4079
4080
#if defined(__cplusplus)
4081
}
4082
#endif /* __cplusplus */
4083
4084
#endif /* MJS_PRIMITIVE_PUBLIC_H_ */
4085
#ifdef MJS_MODULE_LINES
4086
#line 1 "mjs/src/mjs_primitive.h"
4087
#endif
4088
/*
4089
 * Copyright (c) 2016 Cesanta Software Limited
4090
 * All rights reserved
4091
 */
4092
4093
#ifndef MJS_PRIMITIVE_H
4094
#define MJS_PRIMITIVE_H
4095
4096
/* Amalgamated: #include "mjs/src/mjs_primitive_public.h" */
4097
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
4098
4099
#if defined(__cplusplus)
4100
extern "C" {
4101
#endif /* __cplusplus */
4102
4103
/*
4104
 * Convert a pointer to mjs_val_t. If pointer is not valid, mjs crashes.
4105
 */
4106
MJS_PRIVATE mjs_val_t mjs_legit_pointer_to_value(void *p);
4107
4108
/*
4109
 * Convert a pointer to mjs_val_t. If pointer is not valid, error is set
4110
 * in the mjs context.
4111
 */
4112
MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs *mjs, void *p);
4113
4114
/*
4115
 * Extracts a pointer from the mjs_val_t value.
4116
 */
4117
MJS_PRIVATE void *get_ptr(mjs_val_t v);
4118
4119
/*
4120
 * Implementation for JS isNaN()
4121
 */
4122
MJS_PRIVATE void mjs_op_isnan(struct mjs *mjs);
4123
4124
#if defined(__cplusplus)
4125
}
4126
#endif /* __cplusplus */
4127
4128
#endif /* MJS_PRIMITIVE_H */
4129
#ifdef MJS_MODULE_LINES
4130
#line 1 "mjs/src/mjs_string_public.h"
4131
#endif
4132
/*
4133
 * Copyright (c) 2016 Cesanta Software Limited
4134
 * All rights reserved
4135
 */
4136
4137
#ifndef MJS_STRING_PUBLIC_H_
4138
#define MJS_STRING_PUBLIC_H_
4139
4140
/* Amalgamated: #include "mjs/src/mjs_core_public.h" */
4141
4142
#define MJS_STRING_LITERAL_MAX_LEN 128
4143
4144
#if defined(__cplusplus)
4145
extern "C" {
4146
#endif /* __cplusplus */
4147
4148
/*
4149
 * Creates a string primitive value.
4150
 * `str` must point to the utf8 string of length `len`.
4151
 * If `len` is ~0, `str` is assumed to be NUL-terminated and `strlen(str)` is
4152
 * used.
4153
 *
4154
 * If `copy` is non-zero, the string data is copied and owned by the GC. The
4155
 * caller can free the string data afterwards. Otherwise (`copy` is zero), the
4156
 * caller owns the string data, and is responsible for not freeing it while it
4157
 * is used.
4158
 */
4159
mjs_val_t mjs_mk_string(struct mjs *mjs, const char *str, size_t len, int copy);
4160
4161
/* Returns true if given value is a primitive string value */
4162
int mjs_is_string(mjs_val_t v);
4163
4164
/*
4165
 * Returns a pointer to the string stored in `mjs_val_t`.
4166
 *
4167
 * String length returned in `len`, which is allowed to be NULL. Returns NULL
4168
 * if the value is not a string.
4169
 *
4170
 * JS strings can contain embedded NUL chars and may or may not be NUL
4171
 * terminated.
4172
 *
4173
 * CAUTION: creating new JavaScript object, array, or string may kick in a
4174
 * garbage collector, which in turn may relocate string data and invalidate
4175
 * pointer returned by `mjs_get_string()`.
4176
 *
4177
 * Short JS strings are embedded inside the `mjs_val_t` value itself. This
4178
 * is why a pointer to a `mjs_val_t` is required. It also means that the string
4179
 * data will become invalid once that `mjs_val_t` value goes out of scope.
4180
 */
4181
const char *mjs_get_string(struct mjs *mjs, mjs_val_t *v, size_t *len);
4182
4183
/*
4184
 * Returns a pointer to the string stored in `mjs_val_t`.
4185
 *
4186
 * Returns NULL if the value is not a string or if the string is not compatible
4187
 * with a C string.
4188
 *
4189
 * C compatible strings contain exactly one NUL char, in terminal position.
4190
 *
4191
 * All strings owned by the MJS engine (see `mjs_mk_string()`) are guaranteed to
4192
 * be NUL terminated. Out of these, those that don't include embedded NUL chars
4193
 * are guaranteed to be C compatible.
4194
 */
4195
const char *mjs_get_cstring(struct mjs *mjs, mjs_val_t *v);
4196
4197
/*
4198
 * Returns the standard strcmp comparison code after comparing a JS string a
4199
 * with a possibly non null-terminated string b. NOTE: the strings are equal
4200
 * only if their length is equal, i.e. the len field doesn't imply strncmp
4201
 * behaviour.
4202
 */
4203
int mjs_strcmp(struct mjs *mjs, mjs_val_t *a, const char *b, size_t len);
4204
4205
#if defined(__cplusplus)
4206
}
4207
#endif /* __cplusplus */
4208
4209
#endif /* MJS_STRING_PUBLIC_H_ */
4210
#ifdef MJS_MODULE_LINES
4211
#line 1 "mjs/src/mjs_string.h"
4212
#endif
4213
/*
4214
 * Copyright (c) 2016 Cesanta Software Limited
4215
 * All rights reserved
4216
 */
4217
4218
#ifndef MJS_STRING_H_
4219
#define MJS_STRING_H_
4220
4221
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
4222
/* Amalgamated: #include "mjs/src/mjs_string_public.h" */
4223
4224
#if defined(__cplusplus)
4225
extern "C" {
4226
#endif /* __cplusplus */
4227
4228
/*
4229
 * Size of the extra space for strings mbuf that is needed to avoid frequent
4230
 * reallocations
4231
 */
4232
#define _MJS_STRING_BUF_RESERVE 100
4233
4234
MJS_PRIVATE unsigned long cstr_to_ulong(const char *s, size_t len, int *ok);
4235
MJS_PRIVATE mjs_err_t
4236
str_to_ulong(struct mjs *mjs, mjs_val_t v, int *ok, unsigned long *res);
4237
MJS_PRIVATE int s_cmp(struct mjs *mjs, mjs_val_t a, mjs_val_t b);
4238
MJS_PRIVATE mjs_val_t s_concat(struct mjs *mjs, mjs_val_t a, mjs_val_t b);
4239
4240
MJS_PRIVATE void embed_string(struct mbuf *m, size_t offset, const char *p,
4241
                              size_t len, uint8_t /*enum embstr_flags*/ flags);
4242
4243
MJS_PRIVATE void mjs_mkstr(struct mjs *mjs);
4244
4245
MJS_PRIVATE void mjs_string_slice(struct mjs *mjs);
4246
MJS_PRIVATE void mjs_string_index_of(struct mjs *mjs);
4247
MJS_PRIVATE void mjs_string_char_code_at(struct mjs *mjs);
4248
4249
#define EMBSTR_ZERO_TERM 1
4250
#define EMBSTR_UNESCAPE 2
4251
4252
#if defined(__cplusplus)
4253
}
4254
#endif /* __cplusplus */
4255
4256
#endif /* MJS_STRING_H_ */
4257
#ifdef MJS_MODULE_LINES
4258
#line 1 "mjs/src/mjs_util_public.h"
4259
#endif
4260
/*
4261
 * Copyright (c) 2016 Cesanta Software Limited
4262
 * All rights reserved
4263
 */
4264
4265
#ifndef MJS_UTIL_PUBLIC_H_
4266
#define MJS_UTIL_PUBLIC_H_
4267
4268
/* Amalgamated: #include "mjs/src/mjs_core_public.h" */
4269
#include <stdio.h>
4270
4271
#if defined(__cplusplus)
4272
extern "C" {
4273
#endif /* __cplusplus */
4274
4275
const char *mjs_typeof(mjs_val_t v);
4276
4277
void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp);
4278
void mjs_sprintf(mjs_val_t v, struct mjs *mjs, char *buf, size_t buflen);
4279
4280
#if MJS_ENABLE_DEBUG
4281
4282
void mjs_disasm(const uint8_t *code, size_t len);
4283
void mjs_dump(struct mjs *mjs, int do_disasm);
4284
4285
#endif
4286
4287
/*
4288
 * Returns the filename corresponding to the given bcode offset.
4289
 */
4290
const char *mjs_get_bcode_filename_by_offset(struct mjs *mjs, int offset);
4291
4292
/*
4293
 * Returns the line number corresponding to the given bcode offset.
4294
 */
4295
int mjs_get_lineno_by_offset(struct mjs *mjs, int offset);
4296
4297
/*
4298
 * Returns bcode offset of the corresponding call frame cf_num, where 0 means
4299
 * the currently executing function, 1 means the first return address, etc.
4300
 *
4301
 * If given cf_num is too large, -1 is returned.
4302
 */
4303
int mjs_get_offset_by_call_frame_num(struct mjs *mjs, int cf_num);
4304
4305
#if defined(__cplusplus)
4306
}
4307
#endif /* __cplusplus */
4308
4309
#endif /* MJS_UTIL_PUBLIC_H_ */
4310
#ifdef MJS_MODULE_LINES
4311
#line 1 "mjs/src/mjs_util.h"
4312
#endif
4313
/*
4314
 * Copyright (c) 2016 Cesanta Software Limited
4315
 * All rights reserved
4316
 */
4317
4318
#ifndef MJS_UTIL_H_
4319
#define MJS_UTIL_H_
4320
4321
/* Amalgamated: #include "frozen.h" */
4322
/* Amalgamated: #include "mjs/src/mjs_core.h" */
4323
/* Amalgamated: #include "mjs/src/mjs_util_public.h" */
4324
4325
#if defined(__cplusplus)
4326
extern "C" {
4327
#endif /* __cplusplus */
4328
4329
struct mjs_bcode_part;
4330
4331
MJS_PRIVATE const char *opcodetostr(uint8_t opcode);
4332
MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i);
4333
MJS_PRIVATE const char *mjs_stringify_type(enum mjs_type t);
4334
4335
/*
4336
 * Checks that the given argument is provided, and checks its type. If check
4337
 * fails, sets error in the mjs context, and returns 0; otherwise returns 1.
4338
 *
4339
 * If `arg_num` >= 0, checks argument; otherwise (`arg_num` is negative) checks
4340
 * `this`. `arg_name` is used for the error message only. If `parg` is not
4341
 * NULL, writes resulting value at this location in case of success.
4342
 */
4343
MJS_PRIVATE int mjs_check_arg(struct mjs *mjs, int arg_num,
4344
                              const char *arg_name, enum mjs_type expected_type,
4345
                              mjs_val_t *parg);
4346
4347
/*
4348
 * mjs_normalize_idx takes and index in the string and the string size, and
4349
 * returns the index which is >= 0 and <= size. Negative index is interpreted
4350
 * as size + index.
4351
 */
4352
MJS_PRIVATE int mjs_normalize_idx(int idx, int size);
4353
4354
MJS_PRIVATE const char *mjs_get_bcode_filename(struct mjs *mjs,
4355
                                               struct mjs_bcode_part *bp);
4356
4357
/* Print JS value `v` to the JSON stream `out`. */
4358
void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out);
4359
4360
#if defined(__cplusplus)
4361
}
4362
#endif /* __cplusplus */
4363
4364
#endif /* MJS_UTIL_H_ */
4365
#ifdef MJS_MODULE_LINES
4366
#line 1 "common/cs_varint.h"
4367
#endif
4368
/*
4369
 * Copyright (c) 2014-2018 Cesanta Software Limited
4370
 * All rights reserved
4371
 *
4372
 * Licensed under the Apache License, Version 2.0 (the ""License"");
4373
 * you may not use this file except in compliance with the License.
4374
 * You may obtain a copy of the License at
4375
 *
4376
 *     http://www.apache.org/licenses/LICENSE-2.0
4377
 *
4378
 * Unless required by applicable law or agreed to in writing, software
4379
 * distributed under the License is distributed on an ""AS IS"" BASIS,
4380
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4381
 * See the License for the specific language governing permissions and
4382
 * limitations under the License.
4383
 */
4384
4385
#ifndef CS_COMMON_CS_VARINT_H_
4386
#define CS_COMMON_CS_VARINT_H_
4387
4388
#if defined(_WIN32) && _MSC_VER < 1700
4389
typedef unsigned char uint8_t;
4390
typedef unsigned __int64 uint64_t;
4391
#else
4392
#include <stdbool.h>
4393
#include <stdint.h>
4394
#include <stdlib.h>
4395
#endif
4396
4397
#ifdef __cplusplus
4398
extern "C" {
4399
#endif
4400
4401
/* Returns number of bytes required to encode `num`. */
4402
size_t cs_varint_llen(uint64_t num);
4403
4404
/*
4405
 * Encodes `num` into `buf`.
4406
 * Returns number of bytes required to encode `num`.
4407
 * Note: return value may be greater than `buf_size` but the function will only
4408
 * write `buf_size` bytes.
4409
 */
4410
size_t cs_varint_encode(uint64_t num, uint8_t *buf, size_t buf_size);
4411
4412
/*
4413
 * Decodes varint stored in `buf`.
4414
 * Stores the number of bytes consumed into `llen`.
4415
 * If there aren't enough bytes in `buf` to decode a number, returns false.
4416
 */
4417
bool cs_varint_decode(const uint8_t *buf, size_t buf_size, uint64_t *num,
4418
                      size_t *llen);
4419
4420
uint64_t cs_varint_decode_unsafe(const uint8_t *buf, int *llen);
4421
4422
#ifdef __cplusplus
4423
}
4424
#endif
4425
4426
#endif /* CS_COMMON_CS_VARINT_H_ */
4427
#ifdef MJS_MODULE_LINES
4428
#line 1 "mjs/src/mjs_bcode.h"
4429
#endif
4430
/*
4431
 * Copyright (c) 2017 Cesanta Software Limited
4432
 * All rights reserved
4433
 */
4434
4435
#ifndef MJS_BCODE_H_
4436
#define MJS_BCODE_H_
4437
4438
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
4439
4440
/* Amalgamated: #include "mjs/src/mjs_core.h" */
4441
4442
#if defined(__cplusplus)
4443
extern "C" {
4444
#endif /* __cplusplus */
4445
4446
enum mjs_opcode {
4447
  OP_NOP,               /* ( -- ) */
4448
  OP_DROP,              /* ( a -- ) */
4449
  OP_DUP,               /* ( a -- a a ) */
4450
  OP_SWAP,              /* ( a b -- b a ) */
4451
  OP_JMP,               /* ( -- ) */
4452
  OP_JMP_TRUE,          /* ( -- ) */
4453
  OP_JMP_NEUTRAL_TRUE,  /* ( -- ) */
4454
  OP_JMP_FALSE,         /* ( -- ) */
4455
  OP_JMP_NEUTRAL_FALSE, /* ( -- ) */
4456
  OP_FIND_SCOPE,        /* ( a -- a b ) */
4457
  OP_PUSH_SCOPE,        /* ( -- a ) */
4458
  OP_PUSH_STR,          /* ( -- a ) */
4459
  OP_PUSH_TRUE,         /* ( -- a ) */
4460
  OP_PUSH_FALSE,        /* ( -- a ) */
4461
  OP_PUSH_INT,          /* ( -- a ) */
4462
  OP_PUSH_DBL,          /* ( -- a ) */
4463
  OP_PUSH_NULL,         /* ( -- a ) */
4464
  OP_PUSH_UNDEF,        /* ( -- a ) */
4465
  OP_PUSH_OBJ,          /* ( -- a ) */
4466
  OP_PUSH_ARRAY,        /* ( -- a ) */
4467
  OP_PUSH_FUNC,         /* ( -- a ) */
4468
  OP_PUSH_THIS,         /* ( -- a ) */
4469
  OP_GET,               /* ( key obj  -- obj[key] ) */
4470
  OP_CREATE,            /* ( key obj -- ) */
4471
  OP_EXPR,              /* ( ... -- a ) */
4472
  OP_APPEND,            /* ( a b -- ) */
4473
  OP_SET_ARG,           /* ( a -- a ) */
4474
  OP_NEW_SCOPE,         /* ( -- ) */
4475
  OP_DEL_SCOPE,         /* ( -- ) */
4476
  OP_CALL,              /* ( func param1 param2 ... num_params -- result ) */
4477
  OP_RETURN,            /* ( -- ) */
4478
  OP_LOOP,         /* ( -- ) Push break & continue addresses to loop_labels */
4479
  OP_BREAK,        /* ( -- ) */
4480
  OP_CONTINUE,     /* ( -- ) */
4481
  OP_SETRETVAL,    /* ( a -- ) */
4482
  OP_EXIT,         /* ( -- ) */
4483
  OP_BCODE_HEADER, /* ( -- ) */
4484
  OP_ARGS,         /* ( -- ) Mark the beginning of function call arguments */
4485
  OP_FOR_IN_NEXT,  /* ( name obj iter_ptr -- name obj iter_ptr_next ) */
4486
  OP_MAX
4487
};
4488
4489
struct pstate;
4490
struct mjs;
4491
4492
MJS_PRIVATE void emit_byte(struct pstate *pstate, uint8_t byte);
4493
MJS_PRIVATE void emit_int(struct pstate *pstate, int64_t n);
4494
MJS_PRIVATE void emit_str(struct pstate *pstate, const char *ptr, size_t len);
4495
4496
/*
4497
 * Inserts provided offset `v` at the offset `offset`.
4498
 *
4499
 * Returns delta at which the code was moved; the delta can be any: 0 or
4500
 * positive or negative.
4501
 */
4502
MJS_PRIVATE int mjs_bcode_insert_offset(struct pstate *p, struct mjs *mjs,
4503
                                        size_t offset, size_t v);
4504
4505
/*
4506
 * Adds a new bcode part; does not retain `bp`.
4507
 */
4508
MJS_PRIVATE void mjs_bcode_part_add(struct mjs *mjs,
4509
                                    const struct mjs_bcode_part *bp);
4510
4511
/*
4512
 * Returns bcode part by the bcode number
4513
 */
4514
MJS_PRIVATE struct mjs_bcode_part *mjs_bcode_part_get(struct mjs *mjs, int num);
4515
4516
/*
4517
 * Returns bcode part by the global bcode offset
4518
 */
4519
MJS_PRIVATE struct mjs_bcode_part *mjs_bcode_part_get_by_offset(struct mjs *mjs,
4520
                                                                size_t offset);
4521
4522
/*
4523
 * Returns a number of bcode parts
4524
 */
4525
MJS_PRIVATE int mjs_bcode_parts_cnt(struct mjs *mjs);
4526
4527
/*
4528
 * Adds the bcode being generated (mjs->bcode_gen) as a next bcode part
4529
 */
4530
MJS_PRIVATE void mjs_bcode_commit(struct mjs *mjs);
4531
4532
#if defined(__cplusplus)
4533
}
4534
#endif /* __cplusplus */
4535
4536
#endif /* MJS_BCODE_H_ */
4537
#ifdef MJS_MODULE_LINES
4538
#line 1 "mjs/src/mjs_internal.h"
4539
#endif
4540
/*
4541
 * Copyright (c) 2016 Cesanta Software Limited
4542
 * All rights reserved
4543
 */
4544
4545
#ifndef MJS_INTERNAL_H_
4546
#define MJS_INTERNAL_H_
4547
4548
#include <assert.h>
4549
#include <ctype.h>
4550
#include <math.h>
4551
#include <stdarg.h>
4552
#include <stdio.h>
4553
#include <string.h>
4554
4555
#ifndef FAST
4556
#define FAST
4557
#endif
4558
4559
#ifndef STATIC
4560
#define STATIC
4561
#endif
4562
4563
#ifndef ENDL
4564
#define ENDL "\n"
4565
#endif
4566
4567
#ifdef MJS_EXPOSE_PRIVATE
4568
#define MJS_PRIVATE
4569
#define MJS_EXTERN extern
4570
#else
4571
#define MJS_PRIVATE static
4572
#define MJS_EXTERN static
4573
#endif
4574
4575
#ifndef ARRAY_SIZE
4576
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
4577
#endif
4578
4579
#if !defined(WEAK)
4580
#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
4581
#define WEAK __attribute__((weak))
4582
#else
4583
#define WEAK
4584
#endif
4585
#endif
4586
4587
#ifndef CS_ENABLE_STDIO
4588
#define CS_ENABLE_STDIO 1
4589
#endif
4590
4591
/* Amalgamated: #include "common/cs_dbg.h" */
4592
/* Amalgamated: #include "common/cs_file.h" */
4593
/* Amalgamated: #include "common/mbuf.h" */
4594
4595
#if defined(_WIN32) && _MSC_VER < 1700
4596
typedef signed char int8_t;
4597
typedef unsigned char uint8_t;
4598
typedef int int32_t;
4599
typedef unsigned int uint32_t;
4600
typedef short int16_t;
4601
typedef unsigned short uint16_t;
4602
typedef __int64 int64_t;
4603
typedef unsigned long uintptr_t;
4604
#define STRX(x) #x
4605
#define STR(x) STRX(x)
4606
#define __func__ __FILE__ ":" STR(__LINE__)
4607
// #define snprintf _snprintf
4608
#define vsnprintf _vsnprintf
4609
#define isnan(x) _isnan(x)
4610
#define va_copy(x, y) (x) = (y)
4611
#define CS_DEFINE_DIRENT
4612
#include <windows.h>
4613
#else
4614
#if defined(__unix__) || defined(__APPLE__)
4615
#include <dlfcn.h>
4616
#endif
4617
#endif
4618
4619
/*
4620
 * Number of bytes reserved for the jump offset initially. The most practical
4621
 * value is 1, but for testing it's useful to set it to 0 and to some large
4622
 * value as well (like, 4), to make sure that the code behaves correctly under
4623
 * all circumstances.
4624
 */
4625
#ifndef MJS_INIT_OFFSET_SIZE
4626
#define MJS_INIT_OFFSET_SIZE 1
4627
#endif
4628
4629
#endif /* MJS_INTERNAL_H_ */
4630
#ifdef MJS_MODULE_LINES
4631
#line 1 "mjs/src/mjs_tok.h"
4632
#endif
4633
/*
4634
 * Copyright (c) 2016 Cesanta Software Limited
4635
 * All rights reserved
4636
 */
4637
4638
#ifndef MJS_TOK_H_
4639
#define MJS_TOK_H_
4640
4641
/* Amalgamated: #include "mjs_internal.h" */
4642
4643
#if defined(__cplusplus)
4644
extern "C" {
4645
#endif /* __cplusplus */
4646
4647
struct tok {
4648
  int tok;
4649
  int len;
4650
  const char *ptr;
4651
};
4652
4653
struct pstate {
4654
  const char *file_name; /* Source code file name */
4655
  const char *buf;       /* Nul-terminated source code buffer */
4656
  const char *pos;       /* Current position */
4657
  int line_no;           /* Line number */
4658
  int last_emitted_line_no;
4659
  struct mbuf offset_lineno_map;
4660
  int prev_tok;   /* Previous token, for prefix increment / decrement */
4661
  struct tok tok; /* Parsed token */
4662
  struct mjs *mjs;
4663
  int start_bcode_idx; /* Index in mjs->bcode at which parsing was started */
4664
  int cur_idx; /* Index in mjs->bcode at which newly generated code is inserted
4665
                  */
4666
  int depth;
4667
};
4668
4669
enum {
4670
  TOK_EOF,
4671
  TOK_INVALID,
4672
4673
  TOK_COLON,
4674
  TOK_SEMICOLON,
4675
  TOK_COMMA,
4676
  TOK_ASSIGN,
4677
  TOK_OPEN_CURLY,
4678
  TOK_CLOSE_CURLY,
4679
  TOK_OPEN_PAREN,
4680
  TOK_CLOSE_PAREN,
4681
  TOK_OPEN_BRACKET,
4682
  TOK_CLOSE_BRACKET,
4683
  TOK_MUL,
4684
  TOK_PLUS,
4685
  TOK_MINUS,
4686
  TOK_DIV,
4687
  TOK_REM,
4688
  TOK_AND,
4689
  TOK_OR,
4690
  TOK_XOR,
4691
  TOK_DOT,
4692
  TOK_QUESTION,
4693
  TOK_NOT,
4694
  TOK_TILDA,
4695
  TOK_LT,
4696
  TOK_GT,
4697
  TOK_LSHIFT,
4698
  TOK_RSHIFT,
4699
  TOK_MINUS_MINUS,
4700
  TOK_PLUS_PLUS,
4701
  TOK_PLUS_ASSIGN,
4702
  TOK_MINUS_ASSIGN,
4703
  TOK_MUL_ASSIGN,
4704
  TOK_DIV_ASSIGN,
4705
  TOK_AND_ASSIGN,
4706
  TOK_OR_ASSIGN,
4707
  TOK_REM_ASSIGN,
4708
  TOK_XOR_ASSIGN,
4709
  TOK_EQ,
4710
  TOK_NE,
4711
  TOK_LE,
4712
  TOK_GE,
4713
  TOK_LOGICAL_AND,
4714
  TOK_LOGICAL_OR,
4715
  TOK_EQ_EQ,
4716
  TOK_NE_NE,
4717
  TOK_LSHIFT_ASSIGN,
4718
  TOK_RSHIFT_ASSIGN,
4719
  TOK_URSHIFT,
4720
  TOK_URSHIFT_ASSIGN,
4721
4722
  TOK_UNARY_PLUS,
4723
  TOK_UNARY_MINUS,
4724
  TOK_POSTFIX_PLUS,
4725
  TOK_POSTFIX_MINUS,
4726
4727
  TOK_NUM = 200, /* Make sure they don't clash with ascii '+', '{', etc */
4728
  TOK_STR,
4729
  TOK_IDENT,
4730
  TOK_KEYWORD_BREAK,
4731
  TOK_KEYWORD_CASE,
4732
  TOK_KEYWORD_CATCH,
4733
  TOK_KEYWORD_CONTINUE,
4734
  TOK_KEYWORD_DEBUGGER,
4735
  TOK_KEYWORD_DEFAULT,
4736
  TOK_KEYWORD_DELETE,
4737
  TOK_KEYWORD_DO,
4738
  TOK_KEYWORD_ELSE,
4739
  TOK_KEYWORD_FALSE,
4740
  TOK_KEYWORD_FINALLY,
4741
  TOK_KEYWORD_FOR,
4742
  TOK_KEYWORD_FUNCTION,
4743
  TOK_KEYWORD_IF,
4744
  TOK_KEYWORD_IN,
4745
  TOK_KEYWORD_INSTANCEOF,
4746
  TOK_KEYWORD_NEW,
4747
  TOK_KEYWORD_NULL,
4748
  TOK_KEYWORD_RETURN,
4749
  TOK_KEYWORD_SWITCH,
4750
  TOK_KEYWORD_THIS,
4751
  TOK_KEYWORD_THROW,
4752
  TOK_KEYWORD_TRUE,
4753
  TOK_KEYWORD_TRY,
4754
  TOK_KEYWORD_TYPEOF,
4755
  TOK_KEYWORD_VAR,
4756
  TOK_KEYWORD_VOID,
4757
  TOK_KEYWORD_WHILE,
4758
  TOK_KEYWORD_WITH,
4759
  TOK_KEYWORD_LET,
4760
  TOK_KEYWORD_UNDEFINED,
4761
  TOK_MAX
4762
};
4763
4764
MJS_PRIVATE void pinit(const char *file_name, const char *buf, struct pstate *);
4765
MJS_PRIVATE int pnext(struct pstate *);
4766
MJS_PRIVATE int mjs_is_ident(int c);
4767
MJS_PRIVATE int mjs_is_digit(int c);
4768
4769
#if defined(__cplusplus)
4770
}
4771
#endif /* __cplusplus */
4772
4773
#endif /* MJS_TOK_H_ */
4774
#ifdef MJS_MODULE_LINES
4775
#line 1 "mjs/src/mjs_dataview.h"
4776
#endif
4777
/*
4778
 * Copyright (c) 2017 Cesanta Software Limited
4779
 * All rights reserved
4780
 */
4781
4782
#ifndef MJS_DATAVIEW_H_
4783
#define MJS_DATAVIEW_H_
4784
4785
#if defined(__cplusplus)
4786
extern "C" {
4787
#endif /* __cplusplus */
4788
4789
/*
4790
 * Functions for memory introspection.
4791
 * These are supposed to be FFI-ed and used from the JS environment.
4792
 */
4793
4794
void *mjs_mem_to_ptr(unsigned int val);
4795
void *mjs_mem_get_ptr(void *base, int offset);
4796
void mjs_mem_set_ptr(void *ptr, void *val);
4797
double mjs_mem_get_dbl(void *ptr);
4798
void mjs_mem_set_dbl(void *ptr, double val);
4799
double mjs_mem_get_uint(void *ptr, int size, int bigendian);
4800
double mjs_mem_get_int(void *ptr, int size, int bigendian);
4801
void mjs_mem_set_uint(void *ptr, unsigned int val, int size, int bigendian);
4802
void mjs_mem_set_int(void *ptr, int val, int size, int bigendian);
4803
4804
#if defined(__cplusplus)
4805
}
4806
#endif /* __cplusplus */
4807
4808
#endif /* MJS_DATAVIEW_H_ */
4809
#ifdef MJS_MODULE_LINES
4810
#line 1 "mjs/src/mjs_exec_public.h"
4811
#endif
4812
/*
4813
 * Copyright (c) 2016 Cesanta Software Limited
4814
 * All rights reserved
4815
 */
4816
4817
#ifndef MJS_EXEC_PUBLIC_H_
4818
#define MJS_EXEC_PUBLIC_H_
4819
4820
/* Amalgamated: #include "mjs/src/mjs_core_public.h" */
4821
#include <stdio.h>
4822
4823
#if defined(__cplusplus)
4824
extern "C" {
4825
#endif /* __cplusplus */
4826
4827
mjs_err_t mjs_exec(struct mjs *, const char *src, mjs_val_t *res);
4828
mjs_err_t mjs_exec_buf(struct mjs *, const char *src, size_t, mjs_val_t *res);
4829
4830
mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, mjs_val_t *res);
4831
mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func,
4832
                    mjs_val_t this_val, int nargs, mjs_val_t *args);
4833
mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func,
4834
                   mjs_val_t this_val, int nargs, ...);
4835
mjs_val_t mjs_get_this(struct mjs *mjs);
4836
4837
#if defined(__cplusplus)
4838
}
4839
#endif /* __cplusplus */
4840
4841
#endif /* MJS_EXEC_PUBLIC_H_ */
4842
#ifdef MJS_MODULE_LINES
4843
#line 1 "mjs/src/mjs_exec.h"
4844
#endif
4845
/*
4846
 * Copyright (c) 2016 Cesanta Software Limited
4847
 * All rights reserved
4848
 */
4849
4850
#ifndef MJS_EXEC_H_
4851
#define MJS_EXEC_H_
4852
4853
/* Amalgamated: #include "mjs/src/mjs_exec_public.h" */
4854
4855
/*
4856
 * A special bcode offset value which causes mjs_execute() to exit immediately;
4857
 * used in mjs_apply().
4858
 */
4859
#define MJS_BCODE_OFFSET_EXIT ((size_t) 0x7fffffff)
4860
4861
#if defined(__cplusplus)
4862
extern "C" {
4863
#endif /* __cplusplus */
4864
4865
MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res);
4866
4867
#if defined(__cplusplus)
4868
}
4869
#endif /* __cplusplus */
4870
4871
#endif /* MJS_EXEC_H_ */
4872
#ifdef MJS_MODULE_LINES
4873
#line 1 "mjs/src/mjs_json.h"
4874
#endif
4875
/*
4876
 * Copyright (c) 2016 Cesanta Software Limited
4877
 * All rights reserved
4878
 */
4879
4880
#ifndef MJS_JSON_H_
4881
#define MJS_JSON_H_
4882
4883
#if defined(__cplusplus)
4884
extern "C" {
4885
#endif /* __cplusplus */
4886
4887
MJS_PRIVATE mjs_err_t to_json_or_debug(struct mjs *mjs, mjs_val_t v, char *buf,
4888
                                       size_t size, size_t *res_len,
4889
                                       uint8_t is_debug);
4890
4891
MJS_PRIVATE mjs_err_t mjs_json_stringify(struct mjs *mjs, mjs_val_t v,
4892
                                         char *buf, size_t size, char **res);
4893
MJS_PRIVATE void mjs_op_json_stringify(struct mjs *mjs);
4894
MJS_PRIVATE void mjs_op_json_parse(struct mjs *mjs);
4895
4896
MJS_PRIVATE mjs_err_t
4897
mjs_json_parse(struct mjs *mjs, const char *str, size_t len, mjs_val_t *res);
4898
4899
#if defined(__cplusplus)
4900
}
4901
#endif /* __cplusplus */
4902
4903
#endif /* MJS_JSON_H_ */
4904
#ifdef MJS_MODULE_LINES
4905
#line 1 "mjs/src/mjs_builtin.h"
4906
#endif
4907
/*
4908
 * Copyright (c) 2016 Cesanta Software Limited
4909
 * All rights reserved
4910
 */
4911
4912
#ifndef MJS_BUILTIN_H_
4913
#define MJS_BUILTIN_H_
4914
4915
/* Amalgamated: #include "mjs/src/mjs_core_public.h" */
4916
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
4917
4918
#if defined(__cplusplus)
4919
extern "C" {
4920
#endif /* __cplusplus */
4921
4922
void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj);
4923
4924
#if defined(__cplusplus)
4925
}
4926
#endif /* __cplusplus */
4927
4928
#endif /* MJS_BUILTIN_H_ */
4929
#ifdef MJS_MODULE_LINES
4930
#line 1 "mjs/src/mjs_parser.h"
4931
#endif
4932
/*
4933
 * Copyright (c) 2016 Cesanta Software Limited
4934
 * All rights reserved
4935
 */
4936
4937
#ifndef MJS_PARSER_H
4938
#define MJS_PARSER_H
4939
4940
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
4941
4942
#if defined(__cplusplus)
4943
extern "C" {
4944
#endif /* __cplusplus */
4945
4946
MJS_PRIVATE mjs_err_t
4947
mjs_parse(const char *path, const char *buf, struct mjs *);
4948
4949
#if defined(__cplusplus)
4950
}
4951
#endif /* __cplusplus */
4952
4953
#endif /* MJS_PARSER_H */
4954
#ifndef MJS_EXPORT_INTERNAL_HEADERS
4955
#ifdef MJS_MODULE_LINES
4956
#line 1 "common/cs_dbg.c"
4957
#endif
4958
/*
4959
 * Copyright (c) 2014-2018 Cesanta Software Limited
4960
 * All rights reserved
4961
 *
4962
 * Licensed under the Apache License, Version 2.0 (the ""License"");
4963
 * you may not use this file except in compliance with the License.
4964
 * You may obtain a copy of the License at
4965
 *
4966
 *     http://www.apache.org/licenses/LICENSE-2.0
4967
 *
4968
 * Unless required by applicable law or agreed to in writing, software
4969
 * distributed under the License is distributed on an ""AS IS"" BASIS,
4970
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4971
 * See the License for the specific language governing permissions and
4972
 * limitations under the License.
4973
 */
4974
4975
/* Amalgamated: #include "common/cs_dbg.h" */
4976
4977
#include <stdarg.h>
4978
#include <stdio.h>
4979
#include <string.h>
4980
4981
/* Amalgamated: #include "common/cs_time.h" */
4982
/* Amalgamated: #include "common/str_util.h" */
4983
4984
enum cs_log_level cs_log_threshold WEAK =
4985
#if CS_ENABLE_DEBUG
4986
    LL_VERBOSE_DEBUG;
4987
#else
4988
    LL_ERROR;
4989
#endif
4990
4991
static char *s_filter_pattern = NULL;
4992
static size_t s_filter_pattern_len;
4993
4994
void cs_log_set_filter(const char *pattern) WEAK;
4995
4996
#if CS_ENABLE_STDIO
4997
4998
FILE *cs_log_file WEAK = NULL;
4999
5000
#if CS_LOG_ENABLE_TS_DIFF
5001
double cs_log_ts WEAK;
5002
#endif
5003
5004
enum cs_log_level cs_log_cur_msg_level WEAK = LL_NONE;
5005
5006
void cs_log_set_filter(const char *pattern) {
5007
  free(s_filter_pattern);
5008
  if (pattern != NULL) {
5009
    s_filter_pattern = strdup(pattern);
5010
    s_filter_pattern_len = strlen(pattern);
5011
  } else {
5012
    s_filter_pattern = NULL;
5013
    s_filter_pattern_len = 0;
5014
  }
5015
}
5016
5017
int cs_log_print_prefix(enum cs_log_level, const char *, const char *) WEAK;
5018
1297
int cs_log_print_prefix(enum cs_log_level level, const char *func,
5019
                        const char *filename) {
5020
  char prefix[21];
5021
5022
1297
  if (level > cs_log_threshold) return 0;
5023
  if (s_filter_pattern != NULL &&
5024
      mg_match_prefix(s_filter_pattern, s_filter_pattern_len, func) == 0 &&
5025
      mg_match_prefix(s_filter_pattern, s_filter_pattern_len, filename) == 0) {
5026
    return 0;
5027
  }
5028
5029
  strncpy(prefix, func, 20);
5030
  prefix[20] = '\0';
5031
  if (cs_log_file == NULL) cs_log_file = stderr;
5032
  cs_log_cur_msg_level = level;
5033
  fprintf(cs_log_file, "%-20s ", prefix);
5034
#if CS_LOG_ENABLE_TS_DIFF
5035
  {
5036
    double now = cs_time();
5037
    fprintf(cs_log_file, "%7u ", (unsigned int) ((now - cs_log_ts) * 1000000));
5038
    cs_log_ts = now;
5039
  }
5040
#endif
5041
  return 1;
5042
}
5043
5044
void cs_log_printf(const char *fmt, ...) WEAK;
5045
void cs_log_printf(const char *fmt, ...) {
5046
  va_list ap;
5047
  va_start(ap, fmt);
5048
  vfprintf(cs_log_file, fmt, ap);
5049
  va_end(ap);
5050
  fputc('\n', cs_log_file);
5051
  fflush(cs_log_file);
5052
  cs_log_cur_msg_level = LL_NONE;
5053
}
5054
5055
void cs_log_set_file(FILE *file) WEAK;
5056
void cs_log_set_file(FILE *file) {
5057
  cs_log_file = file;
5058
}
5059
5060
#else
5061
5062
void cs_log_set_filter(const char *pattern) {
5063
  (void) pattern;
5064
}
5065
5066
#endif /* CS_ENABLE_STDIO */
5067
5068
void cs_log_set_level(enum cs_log_level level) WEAK;
5069
void cs_log_set_level(enum cs_log_level level) {
5070
  cs_log_threshold = level;
5071
#if CS_LOG_ENABLE_TS_DIFF && CS_ENABLE_STDIO
5072
  cs_log_ts = cs_time();
5073
#endif
5074
}
5075
#ifdef MJS_MODULE_LINES
5076
#line 1 "common/cs_file.c"
5077
#endif
5078
/*
5079
 * Copyright (c) 2014-2018 Cesanta Software Limited
5080
 * All rights reserved
5081
 *
5082
 * Licensed under the Apache License, Version 2.0 (the ""License"");
5083
 * you may not use this file except in compliance with the License.
5084
 * You may obtain a copy of the License at
5085
 *
5086
 *     http://www.apache.org/licenses/LICENSE-2.0
5087
 *
5088
 * Unless required by applicable law or agreed to in writing, software
5089
 * distributed under the License is distributed on an ""AS IS"" BASIS,
5090
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5091
 * See the License for the specific language governing permissions and
5092
 * limitations under the License.
5093
 */
5094
5095
/* Amalgamated: #include "common/cs_file.h" */
5096
5097
#include <stdio.h>
5098
#include <stdlib.h>
5099
5100
#ifdef CS_MMAP
5101
#include <fcntl.h>
5102
#include <sys/mman.h>
5103
#include <sys/stat.h>
5104
#endif
5105
5106
#ifndef EXCLUDE_COMMON
5107
char *cs_read_file(const char *path, size_t *size) WEAK;
5108
char *cs_read_file(const char *path, size_t *size) {
5109
  FILE *fp;
5110
  char *data = NULL;
5111
  if ((fp = fopen(path, "rb")) == NULL) {
5112
  } else if (fseek(fp, 0, SEEK_END) != 0) {
5113
    fclose(fp);
5114
  } else {
5115
    *size = ftell(fp);
5116
    data = (char *) malloc(*size + 1);
5117
    if (data != NULL) {
5118
      fseek(fp, 0, SEEK_SET); /* Some platforms might not have rewind(), Oo */
5119
      if (fread(data, 1, *size, fp) != *size) {
5120
        free(data);
5121
        return NULL;
5122
      }
5123
      data[*size] = '\0';
5124
    }
5125
    fclose(fp);
5126
  }
5127
  return data;
5128
}
5129
#endif /* EXCLUDE_COMMON */
5130
5131
#ifdef CS_MMAP
5132
char *cs_mmap_file(const char *path, size_t *size) WEAK;
5133
char *cs_mmap_file(const char *path, size_t *size) {
5134
  char *r;
5135
  int fd = open(path, O_RDONLY, 0);
5136
  struct stat st;
5137
  if (fd < 0) return NULL;
5138
  fstat(fd, &st);
5139
  *size = (size_t) st.st_size;
5140
  r = (char *) mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
5141
  if (r == MAP_FAILED) return NULL;
5142
  return r;
5143
}
5144
#endif
5145
#ifdef MJS_MODULE_LINES
5146
#line 1 "common/cs_varint.c"
5147
#endif
5148
/*
5149
 * Copyright (c) 2014-2018 Cesanta Software Limited
5150
 * All rights reserved
5151
 *
5152
 * Licensed under the Apache License, Version 2.0 (the ""License"");
5153
 * you may not use this file except in compliance with the License.
5154
 * You may obtain a copy of the License at
5155
 *
5156
 *     http://www.apache.org/licenses/LICENSE-2.0
5157
 *
5158
 * Unless required by applicable law or agreed to in writing, software
5159
 * distributed under the License is distributed on an ""AS IS"" BASIS,
5160
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5161
 * See the License for the specific language governing permissions and
5162
 * limitations under the License.
5163
 */
5164
5165
/* Amalgamated: #include "cs_varint.h" */
5166
5167
720
size_t cs_varint_llen(uint64_t num) {
5168
720
  size_t llen = 0;
5169
5170
  do {
5171
724
    llen++;
5172
724
  } while (num >>= 7);
5173
5174
720
  return llen;
5175
}
5176
5177
720
size_t cs_varint_encode(uint64_t num, uint8_t *buf, size_t buf_size) {
5178
720
  size_t llen = 0;
5179
5180
  do {
5181
724
    uint8_t byte = num & 0x7f;
5182
724
    num >>= 7;
5183
724
    if (num != 0) byte |= 0x80;
5184
724
    if (llen < buf_size) *buf++ = byte;
5185
724
    llen++;
5186
724
  } while (num != 0);
5187
5188
720
  return llen;
5189
}
5190
5191
3375
bool cs_varint_decode(const uint8_t *buf, size_t buf_size, uint64_t *num,
5192
                      size_t *llen) {
5193
3375
  size_t i = 0, shift = 0;
5194
3375
  uint64_t n = 0;
5195
5196
  do {
5197

3381
    if (i == buf_size || i == (8 * sizeof(*num) / 7 + 1)) return false;
5198
    /*
5199
     * Each byte of varint contains 7 bits, in little endian order.
5200
     * MSB is a continuation bit: it tells whether next byte is used.
5201
     */
5202
3381
    n |= ((uint64_t)(buf[i] & 0x7f)) << shift;
5203
    /*
5204
     * First we increment i, then check whether it is within boundary and
5205
     * whether decoded byte had continuation bit set.
5206
     */
5207
3381
    i++;
5208
3381
    shift += 7;
5209

3381
  } while (shift < sizeof(uint64_t) * 8 && (buf[i - 1] & 0x80));
5210
5211
3375
  *num = n;
5212
3375
  *llen = i;
5213
5214
3375
  return true;
5215
}
5216
5217
483
uint64_t cs_varint_decode_unsafe(const uint8_t *buf, int *llen) {
5218
  uint64_t v;
5219
  size_t l;
5220
483
  cs_varint_decode(buf, ~0, &v, &l);
5221
483
  *llen = l;
5222
483
  return v;
5223
}
5224
#ifdef MJS_MODULE_LINES
5225
#line 1 "common/mbuf.c"
5226
#endif
5227
/*
5228
 * Copyright (c) 2014-2018 Cesanta Software Limited
5229
 * All rights reserved
5230
 *
5231
 * Licensed under the Apache License, Version 2.0 (the ""License"");
5232
 * you may not use this file except in compliance with the License.
5233
 * You may obtain a copy of the License at
5234
 *
5235
 *     http://www.apache.org/licenses/LICENSE-2.0
5236
 *
5237
 * Unless required by applicable law or agreed to in writing, software
5238
 * distributed under the License is distributed on an ""AS IS"" BASIS,
5239
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5240
 * See the License for the specific language governing permissions and
5241
 * limitations under the License.
5242
 */
5243
5244
#ifndef EXCLUDE_COMMON
5245
5246
#include <assert.h>
5247
#include <string.h>
5248
/* Amalgamated: #include "common/mbuf.h" */
5249
5250
#ifndef MBUF_REALLOC
5251
#define MBUF_REALLOC realloc
5252
#endif
5253
5254
#ifndef MBUF_FREE
5255
#define MBUF_FREE free
5256
#endif
5257
5258
void mbuf_init(struct mbuf *mbuf, size_t initial_size) WEAK;
5259
1310
void mbuf_init(struct mbuf *mbuf, size_t initial_size) {
5260
1310
  mbuf->len = mbuf->size = 0;
5261
1310
  mbuf->buf = NULL;
5262
1310
  mbuf_resize(mbuf, initial_size);
5263
1310
}
5264
5265
void mbuf_free(struct mbuf *mbuf) WEAK;
5266
948
void mbuf_free(struct mbuf *mbuf) {
5267
948
  if (mbuf->buf != NULL) {
5268
308
    MBUF_FREE(mbuf->buf);
5269
308
    mbuf_init(mbuf, 0);
5270
  }
5271
948
}
5272
5273
void mbuf_resize(struct mbuf *a, size_t new_size) WEAK;
5274
1541
void mbuf_resize(struct mbuf *a, size_t new_size) {
5275

1541
  if (new_size > a->size || (new_size < a->size && new_size >= a->len)) {
5276
227
    char *buf = (char *) MBUF_REALLOC(a->buf, new_size);
5277
    /*
5278
     * In case realloc fails, there's not much we can do, except keep things as
5279
     * they are. Note that NULL is a valid return value from realloc when
5280
     * size == 0, but that is covered too.
5281
     */
5282

227
    if (buf == NULL && new_size != 0) return;
5283
227
    a->buf = buf;
5284
227
    a->size = new_size;
5285
  }
5286
}
5287
5288
void mbuf_trim(struct mbuf *mbuf) WEAK;
5289
66
void mbuf_trim(struct mbuf *mbuf) {
5290
66
  mbuf_resize(mbuf, mbuf->len);
5291
66
}
5292
5293
size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t) WEAK;
5294
1928
size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) {
5295
1928
  char *p = NULL;
5296
5297
1928
  assert(a != NULL);
5298
1928
  assert(a->len <= a->size);
5299
1928
  assert(off <= a->len);
5300
5301
  /* check overflow */
5302
1928
  if (~(size_t) 0 - (size_t) a->buf < len) return 0;
5303
5304
1928
  if (a->len + len <= a->size) {
5305
1315
    memmove(a->buf + off + len, a->buf + off, a->len - off);
5306
1315
    if (buf != NULL) {
5307
645
      memcpy(a->buf + off, buf, len);
5308
    }
5309
1315
    a->len += len;
5310
  } else {
5311
613
    size_t min_size = (a->len + len);
5312
613
    size_t new_size = (size_t)(min_size * MBUF_SIZE_MULTIPLIER);
5313
613
    if (new_size - min_size > MBUF_SIZE_MAX_HEADROOM) {
5314
      new_size = min_size + MBUF_SIZE_MAX_HEADROOM;
5315
    }
5316
613
    p = (char *) MBUF_REALLOC(a->buf, new_size);
5317

613
    if (p == NULL && new_size != min_size) {
5318
      new_size = min_size;
5319
      p = (char *) MBUF_REALLOC(a->buf, new_size);
5320
    }
5321
613
    if (p != NULL) {
5322
613
      a->buf = p;
5323
613
      if (off != a->len) {
5324
        memmove(a->buf + off + len, a->buf + off, a->len - off);
5325
      }
5326
613
      if (buf != NULL) memcpy(a->buf + off, buf, len);
5327
613
      a->len += len;
5328
613
      a->size = new_size;
5329
    } else {
5330
      len = 0;
5331
    }
5332
  }
5333
5334
1928
  return len;
5335
}
5336
5337
size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) WEAK;
5338
651
size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) {
5339
651
  return mbuf_insert(a, a->len, buf, len);
5340
}
5341
5342
void mbuf_remove(struct mbuf *mb, size_t n) WEAK;
5343
void mbuf_remove(struct mbuf *mb, size_t n) {
5344
  if (n > 0 && n <= mb->len) {
5345
    memmove(mb->buf, mb->buf + n, mb->len - n);
5346
    mb->len -= n;
5347
  }
5348
}
5349
5350
#endif /* EXCLUDE_COMMON */
5351
#ifdef MJS_MODULE_LINES
5352
#line 1 "common/mg_str.c"
5353
#endif
5354
/*
5355
 * Copyright (c) 2014-2018 Cesanta Software Limited
5356
 * All rights reserved
5357
 *
5358
 * Licensed under the Apache License, Version 2.0 (the ""License"");
5359
 * you may not use this file except in compliance with the License.
5360
 * You may obtain a copy of the License at
5361
 *
5362
 *     http://www.apache.org/licenses/LICENSE-2.0
5363
 *
5364
 * Unless required by applicable law or agreed to in writing, software
5365
 * distributed under the License is distributed on an ""AS IS"" BASIS,
5366
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5367
 * See the License for the specific language governing permissions and
5368
 * limitations under the License.
5369
 */
5370
5371
/* Amalgamated: #include "common/mg_mem.h" */
5372
/* Amalgamated: #include "common/mg_str.h" */
5373
/* Amalgamated: #include "common/platform.h" */
5374
5375
#include <stdlib.h>
5376
#include <string.h>
5377
5378
int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
5379
5380
struct mg_str mg_mk_str(const char *s) WEAK;
5381
struct mg_str mg_mk_str(const char *s) {
5382
  struct mg_str ret = {s, 0};
5383
  if (s != NULL) ret.len = strlen(s);
5384
  return ret;
5385
}
5386
5387
struct mg_str mg_mk_str_n(const char *s, size_t len) WEAK;
5388
struct mg_str mg_mk_str_n(const char *s, size_t len) {
5389
  struct mg_str ret = {s, len};
5390
  return ret;
5391
}
5392
5393
int mg_vcmp(const struct mg_str *str1, const char *str2) WEAK;
5394
int mg_vcmp(const struct mg_str *str1, const char *str2) {
5395
  size_t n2 = strlen(str2), n1 = str1->len;
5396
  int r = strncmp(str1->p, str2, (n1 < n2) ? n1 : n2);
5397
  if (r == 0) {
5398
    return n1 - n2;
5399
  }
5400
  return r;
5401
}
5402
5403
int mg_vcasecmp(const struct mg_str *str1, const char *str2) WEAK;
5404
int mg_vcasecmp(const struct mg_str *str1, const char *str2) {
5405
  size_t n2 = strlen(str2), n1 = str1->len;
5406
  int r = mg_ncasecmp(str1->p, str2, (n1 < n2) ? n1 : n2);
5407
  if (r == 0) {
5408
    return n1 - n2;
5409
  }
5410
  return r;
5411
}
5412
5413
static struct mg_str mg_strdup_common(const struct mg_str s,
5414
                                      int nul_terminate) {
5415
  struct mg_str r = {NULL, 0};
5416
  if (s.len > 0 && s.p != NULL) {
5417
    char *sc = (char *) MG_MALLOC(s.len + (nul_terminate ? 1 : 0));
5418
    if (sc != NULL) {
5419
      memcpy(sc, s.p, s.len);
5420
      if (nul_terminate) sc[s.len] = '\0';
5421
      r.p = sc;
5422
      r.len = s.len;
5423
    }
5424
  }
5425
  return r;
5426
}
5427
5428
struct mg_str mg_strdup(const struct mg_str s) WEAK;
5429
struct mg_str mg_strdup(const struct mg_str s) {
5430
  return mg_strdup_common(s, 0 /* NUL-terminate */);
5431
}
5432
5433
struct mg_str mg_strdup_nul(const struct mg_str s) WEAK;
5434
struct mg_str mg_strdup_nul(const struct mg_str s) {
5435
  return mg_strdup_common(s, 1 /* NUL-terminate */);
5436
}
5437
5438
const char *mg_strchr(const struct mg_str s, int c) WEAK;
5439
const char *mg_strchr(const struct mg_str s, int c) {
5440
  size_t i;
5441
  for (i = 0; i < s.len; i++) {
5442
    if (s.p[i] == c) return &s.p[i];
5443
  }
5444
  return NULL;
5445
}
5446
5447
int mg_strcmp(const struct mg_str str1, const struct mg_str str2) WEAK;
5448
int mg_strcmp(const struct mg_str str1, const struct mg_str str2) {
5449
  size_t i = 0;
5450
  while (i < str1.len && i < str2.len) {
5451
    if (str1.p[i] < str2.p[i]) return -1;
5452
    if (str1.p[i] > str2.p[i]) return 1;
5453
    i++;
5454
  }
5455
  if (i < str1.len) return 1;
5456
  if (i < str2.len) return -1;
5457
  return 0;
5458
}
5459
5460
int mg_strncmp(const struct mg_str, const struct mg_str, size_t n) WEAK;
5461
int mg_strncmp(const struct mg_str str1, const struct mg_str str2, size_t n) {
5462
  struct mg_str s1 = str1;
5463
  struct mg_str s2 = str2;
5464
5465
  if (s1.len > n) {
5466
    s1.len = n;
5467
  }
5468
  if (s2.len > n) {
5469
    s2.len = n;
5470
  }
5471
  return mg_strcmp(s1, s2);
5472
}
5473
5474
const char *mg_strstr(const struct mg_str haystack,
5475
                      const struct mg_str needle) WEAK;
5476
const char *mg_strstr(const struct mg_str haystack,
5477
                      const struct mg_str needle) {
5478
  size_t i;
5479
  if (needle.len > haystack.len) return NULL;
5480
  for (i = 0; i <= haystack.len - needle.len; i++) {
5481
    if (memcmp(haystack.p + i, needle.p, needle.len) == 0) {
5482
      return haystack.p + i;
5483
    }
5484
  }
5485
  return NULL;
5486
}
5487
#ifdef MJS_MODULE_LINES
5488
#line 1 "common/str_util.c"
5489
#endif
5490
/*
5491
 * Copyright (c) 2014-2018 Cesanta Software Limited
5492
 * All rights reserved
5493
 *
5494
 * Licensed under the Apache License, Version 2.0 (the ""License"");
5495
 * you may not use this file except in compliance with the License.
5496
 * You may obtain a copy of the License at
5497
 *
5498
 *     http://www.apache.org/licenses/LICENSE-2.0
5499
 *
5500
 * Unless required by applicable law or agreed to in writing, software
5501
 * distributed under the License is distributed on an ""AS IS"" BASIS,
5502
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5503
 * See the License for the specific language governing permissions and
5504
 * limitations under the License.
5505
 */
5506
5507
#ifndef EXCLUDE_COMMON
5508
5509
/* Amalgamated: #include "common/str_util.h" */
5510
/* Amalgamated: #include "common/mg_mem.h" */
5511
/* Amalgamated: #include "common/platform.h" */
5512
5513
#ifndef C_DISABLE_BUILTIN_SNPRINTF
5514
#define C_DISABLE_BUILTIN_SNPRINTF 0
5515
#endif
5516
5517
/* Amalgamated: #include "common/mg_mem.h" */
5518
5519
size_t c_strnlen(const char *s, size_t maxlen) WEAK;
5520
size_t c_strnlen(const char *s, size_t maxlen) {
5521
  size_t l = 0;
5522
  for (; l < maxlen && s[l] != '\0'; l++) {
5523
  }
5524
  return l;
5525
}
5526
5527
#define C_SNPRINTF_APPEND_CHAR(ch)       \
5528
  do {                                   \
5529
    if (i < (int) buf_size) buf[i] = ch; \
5530
    i++;                                 \
5531
  } while (0)
5532
5533
#define C_SNPRINTF_FLAG_ZERO 1
5534
5535
#if C_DISABLE_BUILTIN_SNPRINTF
5536
int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
5537
int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
5538
  return vsnprintf(buf, buf_size, fmt, ap);
5539
}
5540
#else
5541
static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags,
5542
                  int field_width) {
5543
  char tmp[40];
5544
  int i = 0, k = 0, neg = 0;
5545
5546
  if (num < 0) {
5547
    neg++;
5548
    num = -num;
5549
  }
5550
5551
  /* Print into temporary buffer - in reverse order */
5552
  do {
5553
    int rem = num % base;
5554
    if (rem < 10) {
5555
      tmp[k++] = '0' + rem;
5556
    } else {
5557
      tmp[k++] = 'a' + (rem - 10);
5558
    }
5559
    num /= base;
5560
  } while (num > 0);
5561
5562
  /* Zero padding */
5563
  if (flags && C_SNPRINTF_FLAG_ZERO) {
5564
    while (k < field_width && k < (int) sizeof(tmp) - 1) {
5565
      tmp[k++] = '0';
5566
    }
5567
  }
5568
5569
  /* And sign */
5570
  if (neg) {
5571
    tmp[k++] = '-';
5572
  }
5573
5574
  /* Now output */
5575
  while (--k >= 0) {
5576
    C_SNPRINTF_APPEND_CHAR(tmp[k]);
5577
  }
5578
5579
  return i;
5580
}
5581
5582
int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) WEAK;
5583
int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
5584
  int ch, i = 0, len_mod, flags, precision, field_width;
5585
5586
  while ((ch = *fmt++) != '\0') {
5587
    if (ch != '%') {
5588
      C_SNPRINTF_APPEND_CHAR(ch);
5589
    } else {
5590
      /*
5591
       * Conversion specification:
5592
       *   zero or more flags (one of: # 0 - <space> + ')
5593
       *   an optional minimum  field  width (digits)
5594
       *   an  optional precision (. followed by digits, or *)
5595
       *   an optional length modifier (one of: hh h l ll L q j z t)
5596
       *   conversion specifier (one of: d i o u x X e E f F g G a A c s p n)
5597
       */
5598
      flags = field_width = precision = len_mod = 0;
5599
5600
      /* Flags. only zero-pad flag is supported. */
5601
      if (*fmt == '0') {
5602
        flags |= C_SNPRINTF_FLAG_ZERO;
5603
      }
5604
5605
      /* Field width */
5606
      while (*fmt >= '0' && *fmt <= '9') {
5607
        field_width *= 10;
5608
        field_width += *fmt++ - '0';
5609
      }
5610
      /* Dynamic field width */
5611
      if (*fmt == '*') {
5612
        field_width = va_arg(ap, int);
5613
        fmt++;
5614
      }
5615
5616
      /* Precision */
5617
      if (*fmt == '.') {
5618
        fmt++;
5619
        if (*fmt == '*') {
5620
          precision = va_arg(ap, int);
5621
          fmt++;
5622
        } else {
5623
          while (*fmt >= '0' && *fmt <= '9') {
5624
            precision *= 10;
5625
            precision += *fmt++ - '0';
5626
          }
5627
        }
5628
      }
5629
5630
      /* Length modifier */
5631
      switch (*fmt) {
5632
        case 'h':
5633
        case 'l':
5634
        case 'L':
5635
        case 'I':
5636
        case 'q':
5637
        case 'j':
5638
        case 'z':
5639
        case 't':
5640
          len_mod = *fmt++;
5641
          if (*fmt == 'h') {
5642
            len_mod = 'H';
5643
            fmt++;
5644
          }
5645
          if (*fmt == 'l') {
5646
            len_mod = 'q';
5647
            fmt++;
5648
          }
5649
          break;
5650
      }
5651
5652
      ch = *fmt++;
5653
      if (ch == 's') {
5654
        const char *s = va_arg(ap, const char *); /* Always fetch parameter */
5655
        int j;
5656
        int pad = field_width - (precision >= 0 ? c_strnlen(s, precision) : 0);
5657
        for (j = 0; j < pad; j++) {
5658
          C_SNPRINTF_APPEND_CHAR(' ');
5659
        }
5660
5661
        /* `s` may be NULL in case of %.*s */
5662
        if (s != NULL) {
5663
          /* Ignore negative and 0 precisions */
5664
          for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) {
5665
            C_SNPRINTF_APPEND_CHAR(s[j]);
5666
          }
5667
        }
5668
      } else if (ch == 'c') {
5669
        ch = va_arg(ap, int); /* Always fetch parameter */
5670
        C_SNPRINTF_APPEND_CHAR(ch);
5671
      } else if (ch == 'd' && len_mod == 0) {
5672
        i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags,
5673
                    field_width);
5674
      } else if (ch == 'd' && len_mod == 'l') {
5675
        i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags,
5676
                    field_width);
5677
#ifdef SSIZE_MAX
5678
      } else if (ch == 'd' && len_mod == 'z') {
5679
        i += c_itoa(buf + i, buf_size - i, va_arg(ap, ssize_t), 10, flags,
5680
                    field_width);
5681
#endif
5682
      } else if (ch == 'd' && len_mod == 'q') {
5683
        i += c_itoa(buf + i, buf_size - i, va_arg(ap, int64_t), 10, flags,
5684
                    field_width);
5685
      } else if ((ch == 'x' || ch == 'u') && len_mod == 0) {
5686
        i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned),
5687
                    ch == 'x' ? 16 : 10, flags, field_width);
5688
      } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') {
5689
        i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long),
5690
                    ch == 'x' ? 16 : 10, flags, field_width);
5691
      } else if ((ch == 'x' || ch == 'u') && len_mod == 'z') {
5692
        i += c_itoa(buf + i, buf_size - i, va_arg(ap, size_t),
5693
                    ch == 'x' ? 16 : 10, flags, field_width);
5694
      } else if (ch == 'p') {
5695
        unsigned long num = (unsigned long) (uintptr_t) va_arg(ap, void *);
5696
        C_SNPRINTF_APPEND_CHAR('0');
5697
        C_SNPRINTF_APPEND_CHAR('x');
5698
        i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
5699
      } else {
5700
#ifndef NO_LIBC
5701
        /*
5702
         * TODO(lsm): abort is not nice in a library, remove it
5703
         * Also, ESP8266 SDK doesn't have it
5704
         */
5705
        abort();
5706
#endif
5707
      }
5708
    }
5709
  }
5710
5711
  /* Zero-terminate the result */
5712
  if (buf_size > 0) {
5713
    buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0';
5714
  }
5715
5716
  return i;
5717
}
5718
#endif
5719
5720
int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) WEAK;
5721
int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) {
5722
  int result;
5723
  va_list ap;
5724
  va_start(ap, fmt);
5725
  result = c_vsnprintf(buf, buf_size, fmt, ap);
5726
  va_end(ap);
5727
  return result;
5728
}
5729
5730
#ifdef _WIN32
5731
int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
5732
  int ret;
5733
  char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
5734
5735
  strncpy(buf, path, sizeof(buf));
5736
  buf[sizeof(buf) - 1] = '\0';
5737
5738
  /* Trim trailing slashes. Leave backslash for paths like "X:\" */
5739
  p = buf + strlen(buf) - 1;
5740
  while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
5741
5742
  memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
5743
  ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
5744
5745
  /*
5746
   * Convert back to Unicode. If doubly-converted string does not match the
5747
   * original, something is fishy, reject.
5748
   */
5749
  WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
5750
                      NULL, NULL);
5751
  if (strcmp(buf, buf2) != 0) {
5752
    wbuf[0] = L'\0';
5753
    ret = 0;
5754
  }
5755
5756
  return ret;
5757
}
5758
#endif /* _WIN32 */
5759
5760
/* The simplest O(mn) algorithm. Better implementation are GPLed */
5761
const char *c_strnstr(const char *s, const char *find, size_t slen) WEAK;
5762
const char *c_strnstr(const char *s, const char *find, size_t slen) {
5763
  size_t find_length = strlen(find);
5764
  size_t i;
5765
5766
  for (i = 0; i < slen; i++) {
5767
    if (i + find_length > slen) {
5768
      return NULL;
5769
    }
5770
5771
    if (strncmp(&s[i], find, find_length) == 0) {
5772
      return &s[i];
5773
    }
5774
  }
5775
5776
  return NULL;
5777
}
5778
5779
#if CS_ENABLE_STRDUP
5780
char *strdup(const char *src) WEAK;
5781
char *strdup(const char *src) {
5782
  size_t len = strlen(src) + 1;
5783
  char *ret = MG_MALLOC(len);
5784
  if (ret != NULL) {
5785
    strcpy(ret, src);
5786
  }
5787
  return ret;
5788
}
5789
#endif
5790
5791
void cs_to_hex(char *to, const unsigned char *p, size_t len) WEAK;
5792
void cs_to_hex(char *to, const unsigned char *p, size_t len) {
5793
  static const char *hex = "0123456789abcdef";
5794
5795
  for (; len--; p++) {
5796
    *to++ = hex[p[0] >> 4];
5797
    *to++ = hex[p[0] & 0x0f];
5798
  }
5799
  *to = '\0';
5800
}
5801
5802
static int fourbit(int ch) {
5803
  if (ch >= '0' && ch <= '9') {
5804
    return ch - '0';
5805
  } else if (ch >= 'a' && ch <= 'f') {
5806
    return ch - 'a' + 10;
5807
  } else if (ch >= 'A' && ch <= 'F') {
5808
    return ch - 'A' + 10;
5809
  }
5810
  return 0;
5811
}
5812
5813
void cs_from_hex(char *to, const char *p, size_t len) WEAK;
5814
void cs_from_hex(char *to, const char *p, size_t len) {
5815
  size_t i;
5816
5817
  for (i = 0; i < len; i += 2) {
5818
    *to++ = (fourbit(p[i]) << 4) + fourbit(p[i + 1]);
5819
  }
5820
  *to = '\0';
5821
}
5822
5823
#if CS_ENABLE_TO64
5824
int64_t cs_to64(const char *s) WEAK;
5825
int64_t cs_to64(const char *s) {
5826
  int64_t result = 0;
5827
  int64_t neg = 1;
5828
  while (*s && isspace((unsigned char) *s)) s++;
5829
  if (*s == '-') {
5830
    neg = -1;
5831
    s++;
5832
  }
5833
  while (isdigit((unsigned char) *s)) {
5834
    result *= 10;
5835
    result += (*s - '0');
5836
    s++;
5837
  }
5838
  return result * neg;
5839
}
5840
#endif
5841
5842
static int str_util_lowercase(const char *s) {
5843
  return tolower(*(const unsigned char *) s);
5844
}
5845
5846
int mg_ncasecmp(const char *s1, const char *s2, size_t len) WEAK;
5847
int mg_ncasecmp(const char *s1, const char *s2, size_t len) {
5848
  int diff = 0;
5849
5850
  if (len > 0) do {
5851
      diff = str_util_lowercase(s1++) - str_util_lowercase(s2++);
5852
    } while (diff == 0 && s1[-1] != '\0' && --len > 0);
5853
5854
  return diff;
5855
}
5856
5857
int mg_casecmp(const char *s1, const char *s2) WEAK;
5858
int mg_casecmp(const char *s1, const char *s2) {
5859
  return mg_ncasecmp(s1, s2, (size_t) ~0);
5860
}
5861
5862
int mg_asprintf(char **buf, size_t size, const char *fmt, ...) WEAK;
5863
50
int mg_asprintf(char **buf, size_t size, const char *fmt, ...) {
5864
  int ret;
5865
  va_list ap;
5866
50
  va_start(ap, fmt);
5867
50
  ret = mg_avprintf(buf, size, fmt, ap);
5868
50
  va_end(ap);
5869
50
  return ret;
5870
}
5871
5872
int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) WEAK;
5873
112
int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
5874
  va_list ap_copy;
5875
  int len;
5876
5877
112
  va_copy(ap_copy, ap);
5878
112
  len = vsnprintf(*buf, size, fmt, ap_copy);
5879
112
  va_end(ap_copy);
5880
5881
112
  if (len < 0) {
5882
    /* eCos and Windows are not standard-compliant and return -1 when
5883
     * the buffer is too small. Keep allocating larger buffers until we
5884
     * succeed or out of memory. */
5885
    *buf = NULL; /* LCOV_EXCL_START */
5886
    while (len < 0) {
5887
      MG_FREE(*buf);
5888
      if (size == 0) {
5889
        size = 5;
5890
      }
5891
      size *= 2;
5892
      if ((*buf = (char *) MG_MALLOC(size)) == NULL) {
5893
        len = -1;
5894
        break;
5895
      }
5896
      va_copy(ap_copy, ap);
5897
      len = vsnprintf(*buf, size - 1, fmt, ap_copy);
5898
      va_end(ap_copy);
5899
    }
5900
5901
    /*
5902
     * Microsoft version of vsnprintf() is not always null-terminated, so put
5903
     * the terminator manually
5904
     */
5905
    (*buf)[len] = 0;
5906
    /* LCOV_EXCL_STOP */
5907
112
  } else if (len >= (int) size) {
5908
    /* Standard-compliant code path. Allocate a buffer that is large enough. */
5909
112
    if ((*buf = (char *) MG_MALLOC(len + 1)) == NULL) {
5910
      len = -1; /* LCOV_EXCL_LINE */
5911
    } else {    /* LCOV_EXCL_LINE */
5912
112
      va_copy(ap_copy, ap);
5913
112
      len = vsnprintf(*buf, len + 1, fmt, ap_copy);
5914
112
      va_end(ap_copy);
5915
    }
5916
  }
5917
5918
112
  return len;
5919
}
5920
5921
const char *mg_next_comma_list_entry(const char *, struct mg_str *,
5922
                                     struct mg_str *) WEAK;
5923
const char *mg_next_comma_list_entry(const char *list, struct mg_str *val,
5924
                                     struct mg_str *eq_val) {
5925
  struct mg_str ret = mg_next_comma_list_entry_n(mg_mk_str(list), val, eq_val);
5926
  return ret.p;
5927
}
5928
5929
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
5930
                                         struct mg_str *eq_val) WEAK;
5931
struct mg_str mg_next_comma_list_entry_n(struct mg_str list, struct mg_str *val,
5932
                                         struct mg_str *eq_val) {
5933
  if (list.len == 0) {
5934
    /* End of the list */
5935
    list = mg_mk_str(NULL);
5936
  } else {
5937
    const char *chr = NULL;
5938
    *val = list;
5939
5940
    if ((chr = mg_strchr(*val, ',')) != NULL) {
5941
      /* Comma found. Store length and shift the list ptr */
5942
      val->len = chr - val->p;
5943
      chr++;
5944
      list.len -= (chr - list.p);
5945
      list.p = chr;
5946
    } else {
5947
      /* This value is the last one */
5948
      list = mg_mk_str_n(list.p + list.len, 0);
5949
    }
5950
5951
    if (eq_val != NULL) {
5952
      /* Value has form "x=y", adjust pointers and lengths */
5953
      /* so that val points to "x", and eq_val points to "y". */
5954
      eq_val->len = 0;
5955
      eq_val->p = (const char *) memchr(val->p, '=', val->len);
5956
      if (eq_val->p != NULL) {
5957
        eq_val->p++; /* Skip over '=' character */
5958
        eq_val->len = val->p + val->len - eq_val->p;
5959
        val->len = (eq_val->p - val->p) - 1;
5960
      }
5961
    }
5962
  }
5963
5964
  return list;
5965
}
5966
5967
size_t mg_match_prefix_n(const struct mg_str, const struct mg_str) WEAK;
5968
size_t mg_match_prefix_n(const struct mg_str pattern, const struct mg_str str) {
5969
  const char *or_str;
5970
  size_t res = 0, len = 0, i = 0, j = 0;
5971
5972
  if ((or_str = (const char *) memchr(pattern.p, '|', pattern.len)) != NULL ||
5973
      (or_str = (const char *) memchr(pattern.p, ',', pattern.len)) != NULL) {
5974
    struct mg_str pstr = {pattern.p, (size_t)(or_str - pattern.p)};
5975
    res = mg_match_prefix_n(pstr, str);
5976
    if (res > 0) return res;
5977
    pstr.p = or_str + 1;
5978
    pstr.len = (pattern.p + pattern.len) - (or_str + 1);
5979
    return mg_match_prefix_n(pstr, str);
5980
  }
5981
5982
  for (; i < pattern.len && j < str.len; i++, j++) {
5983
    if (pattern.p[i] == '?') {
5984
      continue;
5985
    } else if (pattern.p[i] == '*') {
5986
      i++;
5987
      if (i < pattern.len && pattern.p[i] == '*') {
5988
        i++;
5989
        len = str.len - j;
5990
      } else {
5991
        len = 0;
5992
        while (j + len < str.len && str.p[j + len] != '/') len++;
5993
      }
5994
      if (i == pattern.len || (pattern.p[i] == '$' && i == pattern.len - 1))
5995
        return j + len;
5996
      do {
5997
        const struct mg_str pstr = {pattern.p + i, pattern.len - i};
5998
        const struct mg_str sstr = {str.p + j + len, str.len - j - len};
5999
        res = mg_match_prefix_n(pstr, sstr);
6000
      } while (res == 0 && len != 0 && len-- > 0);
6001
      return res == 0 ? 0 : j + res + len;
6002
    } else if (str_util_lowercase(&pattern.p[i]) !=
6003
               str_util_lowercase(&str.p[j])) {
6004
      break;
6005
    }
6006
  }
6007
  if (i < pattern.len && pattern.p[i] == '$') {
6008
    return j == str.len ? str.len : 0;
6009
  }
6010
  return i == pattern.len ? j : 0;
6011
}
6012
6013
size_t mg_match_prefix(const char *, int, const char *) WEAK;
6014
size_t mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
6015
  const struct mg_str pstr = {pattern, (size_t) pattern_len};
6016
  struct mg_str s = {str, 0};
6017
  if (str != NULL) s.len = strlen(str);
6018
  return mg_match_prefix_n(pstr, s);
6019
}
6020
6021
#endif /* EXCLUDE_COMMON */
6022
#ifdef MJS_MODULE_LINES
6023
#line 1 "frozen/frozen.c"
6024
#endif
6025
/*
6026
 * Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
6027
 * Copyright (c) 2018 Cesanta Software Limited
6028
 * All rights reserved
6029
 *
6030
 * Licensed under the Apache License, Version 2.0 (the ""License"");
6031
 * you may not use this file except in compliance with the License.
6032
 * You may obtain a copy of the License at
6033
 *
6034
 *     http://www.apache.org/licenses/LICENSE-2.0
6035
 *
6036
 * Unless required by applicable law or agreed to in writing, software
6037
 * distributed under the License is distributed on an ""AS IS"" BASIS,
6038
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
6039
 * See the License for the specific language governing permissions and
6040
 * limitations under the License.
6041
 */
6042
6043
#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */
6044
6045
/* Amalgamated: #include "frozen.h" */
6046
#include <ctype.h>
6047
#include <stdarg.h>
6048
#include <stdio.h>
6049
#include <stdlib.h>
6050
#include <string.h>
6051
6052
#if !defined(WEAK)
6053
#if (defined(__GNUC__) || defined(__TI_COMPILER_VERSION__)) && !defined(_WIN32)
6054
#define WEAK __attribute__((weak))
6055
#else
6056
#define WEAK
6057
#endif
6058
#endif
6059
6060
#ifdef _WIN32
6061
#undef snprintf
6062
#undef vsnprintf
6063
#define snprintf cs_win_snprintf
6064
#define vsnprintf cs_win_vsnprintf
6065
int cs_win_snprintf(char *str, size_t size, const char *format, ...);
6066
int cs_win_vsnprintf(char *str, size_t size, const char *format, va_list ap);
6067
#if _MSC_VER >= 1700
6068
#include <stdint.h>
6069
#else
6070
typedef _int64 int64_t;
6071
typedef unsigned _int64 uint64_t;
6072
#endif
6073
#define PRId64 "I64d"
6074
#define PRIu64 "I64u"
6075
#else /* _WIN32 */
6076
/* <inttypes.h> wants this for C++ */
6077
#ifndef __STDC_FORMAT_MACROS
6078
#define __STDC_FORMAT_MACROS
6079
#endif
6080
#include <inttypes.h>
6081
#endif /* _WIN32 */
6082
6083
#ifndef INT64_FMT
6084
#define INT64_FMT PRId64
6085
#endif
6086
#ifndef UINT64_FMT
6087
#define UINT64_FMT PRIu64
6088
#endif
6089
6090
#ifndef va_copy
6091
#define va_copy(x, y) x = y
6092
#endif
6093
6094
#ifndef JSON_MAX_PATH_LEN
6095
#define JSON_MAX_PATH_LEN 256
6096
#endif
6097
6098
struct frozen {
6099
  const char *end;
6100
  const char *cur;
6101
6102
  const char *cur_name;
6103
  size_t cur_name_len;
6104
6105
  /* For callback API */
6106
  char path[JSON_MAX_PATH_LEN];
6107
  size_t path_len;
6108
  void *callback_data;
6109
  json_walk_callback_t callback;
6110
};
6111
6112
struct fstate {
6113
  const char *ptr;
6114
  size_t path_len;
6115
};
6116
6117
#define SET_STATE(fr, ptr, str, len)              \
6118
  struct fstate fstate = {(ptr), (fr)->path_len}; \
6119
  append_to_path((fr), (str), (len));
6120
6121
#define CALL_BACK(fr, tok, value, len)                                        \
6122
  do {                                                                        \
6123
    if ((fr)->callback &&                                                     \
6124
        ((fr)->path_len == 0 || (fr)->path[(fr)->path_len - 1] != '.')) {     \
6125
      struct json_token t = {(value), (len), (tok)};                          \
6126
                                                                              \
6127
      /* Call the callback with the given value and current name */           \
6128
      (fr)->callback((fr)->callback_data, (fr)->cur_name, (fr)->cur_name_len, \
6129
                     (fr)->path, &t);                                         \
6130
                                                                              \
6131
      /* Reset the name */                                                    \
6132
      (fr)->cur_name = NULL;                                                  \
6133
      (fr)->cur_name_len = 0;                                                 \
6134
    }                                                                         \
6135
  } while (0)
6136
6137
static int append_to_path(struct frozen *f, const char *str, int size) {
6138
  int n = f->path_len;
6139
  int left = sizeof(f->path) - n - 1;
6140
  if (size > left) size = left;
6141
  memcpy(f->path + n, str, size);
6142
  f->path[n + size] = '\0';
6143
  f->path_len += size;
6144
  return n;
6145
}
6146
6147
static void truncate_path(struct frozen *f, size_t len) {
6148
  f->path_len = len;
6149
  f->path[len] = '\0';
6150
}
6151
6152
static int parse_object(struct frozen *f);
6153
static int parse_value(struct frozen *f);
6154
6155
#define EXPECT(cond, err_code)      \
6156
  do {                              \
6157
    if (!(cond)) return (err_code); \
6158
  } while (0)
6159
6160
#define TRY(expr)          \
6161
  do {                     \
6162
    int _n = expr;         \
6163
    if (_n < 0) return _n; \
6164
  } while (0)
6165
6166
#define END_OF_STRING (-1)
6167
6168
static int left(const struct frozen *f) {
6169
  return f->end - f->cur;
6170
}
6171
6172
static int is_space(int ch) {
6173
  return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
6174
}
6175
6176
static void skip_whitespaces(struct frozen *f) {
6177
  while (f->cur < f->end && is_space(*f->cur)) f->cur++;
6178
}
6179
6180
static int cur(struct frozen *f) {
6181
  skip_whitespaces(f);
6182
  return f->cur >= f->end ? END_OF_STRING : *(unsigned char *) f->cur;
6183
}
6184
6185
static int test_and_skip(struct frozen *f, int expected) {
6186
  int ch = cur(f);
6187
  if (ch == expected) {
6188
    f->cur++;
6189
    return 0;
6190
  }
6191
  return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
6192
}
6193
6194
static int is_alpha(int ch) {
6195
  return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
6196
}
6197
6198
static int is_digit(int ch) {
6199
  return ch >= '0' && ch <= '9';
6200
}
6201
6202
static int is_hex_digit(int ch) {
6203
  return is_digit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
6204
}
6205
6206
static int get_escape_len(const char *s, int len) {
6207
  switch (*s) {
6208
    case 'u':
6209
      return len < 6 ? JSON_STRING_INCOMPLETE
6210
                     : is_hex_digit(s[1]) && is_hex_digit(s[2]) &&
6211
                               is_hex_digit(s[3]) && is_hex_digit(s[4])
6212
                           ? 5
6213
                           : JSON_STRING_INVALID;
6214
    case '"':
6215
    case '\\':
6216
    case '/':
6217
    case 'b':
6218
    case 'f':
6219
    case 'n':
6220
    case 'r':
6221
    case 't':
6222
      return len < 2 ? JSON_STRING_INCOMPLETE : 1;
6223
    default:
6224
      return JSON_STRING_INVALID;
6225
  }
6226
}
6227
6228
/* identifier = letter { letter | digit | '_' } */
6229
static int parse_identifier(struct frozen *f) {
6230
  EXPECT(is_alpha(cur(f)), JSON_STRING_INVALID);
6231
  {
6232
    SET_STATE(f, f->cur, "", 0);
6233
    while (f->cur < f->end &&
6234
           (*f->cur == '_' || is_alpha(*f->cur) || is_digit(*f->cur))) {
6235
      f->cur++;
6236
    }
6237
    truncate_path(f, fstate.path_len);
6238
    CALL_BACK(f, JSON_TYPE_STRING, fstate.ptr, f->cur - fstate.ptr);
6239
  }
6240
  return 0;
6241
}
6242
6243
static int get_utf8_char_len(unsigned char ch) {
6244
  if ((ch & 0x80) == 0) return 1;
6245
  switch (ch & 0xf0) {
6246
    case 0xf0:
6247
      return 4;
6248
    case 0xe0:
6249
      return 3;
6250
    default:
6251
      return 2;
6252
  }
6253
}
6254
6255
/* string = '"' { quoted_printable_chars } '"' */
6256
static int parse_string(struct frozen *f) {
6257
  int n, ch = 0, len = 0;
6258
  TRY(test_and_skip(f, '"'));
6259
  {
6260
    SET_STATE(f, f->cur, "", 0);
6261
    for (; f->cur < f->end; f->cur += len) {
6262
      ch = *(unsigned char *) f->cur;
6263
      len = get_utf8_char_len((unsigned char) ch);
6264
      EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */
6265
      EXPECT(len <= left(f), JSON_STRING_INCOMPLETE);
6266
      if (ch == '\\') {
6267
        EXPECT((n = get_escape_len(f->cur + 1, left(f))) > 0, n);
6268
        len += n;
6269
      } else if (ch == '"') {
6270
        truncate_path(f, fstate.path_len);
6271
        CALL_BACK(f, JSON_TYPE_STRING, fstate.ptr, f->cur - fstate.ptr);
6272
        f->cur++;
6273
        break;
6274
      };
6275
    }
6276
  }
6277
  return ch == '"' ? 0 : JSON_STRING_INCOMPLETE;
6278
}
6279
6280
/* number = [ '-' ] digit+ [ '.' digit+ ] [ ['e'|'E'] ['+'|'-'] digit+ ] */
6281
static int parse_number(struct frozen *f) {
6282
  int ch = cur(f);
6283
  SET_STATE(f, f->cur, "", 0);
6284
  if (ch == '-') f->cur++;
6285
  EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
6286
  EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID);
6287
  while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
6288
  if (f->cur < f->end && f->cur[0] == '.') {
6289
    f->cur++;
6290
    EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
6291
    EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID);
6292
    while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
6293
  }
6294
  if (f->cur < f->end && (f->cur[0] == 'e' || f->cur[0] == 'E')) {
6295
    f->cur++;
6296
    EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
6297
    if ((f->cur[0] == '+' || f->cur[0] == '-')) f->cur++;
6298
    EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
6299
    EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID);
6300
    while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
6301
  }
6302
  truncate_path(f, fstate.path_len);
6303
  CALL_BACK(f, JSON_TYPE_NUMBER, fstate.ptr, f->cur - fstate.ptr);
6304
  return 0;
6305
}
6306
6307
/* array = '[' [ value { ',' value } ] ']' */
6308
static int parse_array(struct frozen *f) {
6309
  int i = 0, current_path_len;
6310
  char buf[20];
6311
  CALL_BACK(f, JSON_TYPE_ARRAY_START, NULL, 0);
6312
  TRY(test_and_skip(f, '['));
6313
  {
6314
    {
6315
      SET_STATE(f, f->cur - 1, "", 0);
6316
      while (cur(f) != ']') {
6317
        snprintf(buf, sizeof(buf), "[%d]", i);
6318
        i++;
6319
        current_path_len = append_to_path(f, buf, strlen(buf));
6320
        f->cur_name =
6321
            f->path + strlen(f->path) - strlen(buf) + 1 /*opening brace*/;
6322
        f->cur_name_len = strlen(buf) - 2 /*braces*/;
6323
        TRY(parse_value(f));
6324
        truncate_path(f, current_path_len);
6325
        if (cur(f) == ',') f->cur++;
6326
      }
6327
      TRY(test_and_skip(f, ']'));
6328
      truncate_path(f, fstate.path_len);
6329
      CALL_BACK(f, JSON_TYPE_ARRAY_END, fstate.ptr, f->cur - fstate.ptr);
6330
    }
6331
  }
6332
  return 0;
6333
}
6334
6335
static int expect(struct frozen *f, const char *s, int len,
6336
                  enum json_token_type tok_type) {
6337
  int i, n = left(f);
6338
  SET_STATE(f, f->cur, "", 0);
6339
  for (i = 0; i < len; i++) {
6340
    if (i >= n) return JSON_STRING_INCOMPLETE;
6341
    if (f->cur[i] != s[i]) return JSON_STRING_INVALID;
6342
  }
6343
  f->cur += len;
6344
  truncate_path(f, fstate.path_len);
6345
6346
  CALL_BACK(f, tok_type, fstate.ptr, f->cur - fstate.ptr);
6347
6348
  return 0;
6349
}
6350
6351
/* value = 'null' | 'true' | 'false' | number | string | array | object */
6352
static int parse_value(struct frozen *f) {
6353
  int ch = cur(f);
6354
6355
  switch (ch) {
6356
    case '"':
6357
      TRY(parse_string(f));
6358
      break;
6359
    case '{':
6360
      TRY(parse_object(f));
6361
      break;
6362
    case '[':
6363
      TRY(parse_array(f));
6364
      break;
6365
    case 'n':
6366
      TRY(expect(f, "null", 4, JSON_TYPE_NULL));
6367
      break;
6368
    case 't':
6369
      TRY(expect(f, "true", 4, JSON_TYPE_TRUE));
6370
      break;
6371
    case 'f':
6372
      TRY(expect(f, "false", 5, JSON_TYPE_FALSE));
6373
      break;
6374
    case '-':
6375
    case '0':
6376
    case '1':
6377
    case '2':
6378
    case '3':
6379
    case '4':
6380
    case '5':
6381
    case '6':
6382
    case '7':
6383
    case '8':
6384
    case '9':
6385
      TRY(parse_number(f));
6386
      break;
6387
    default:
6388
      return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
6389
  }
6390
6391
  return 0;
6392
}
6393
6394
/* key = identifier | string */
6395
static int parse_key(struct frozen *f) {
6396
  int ch = cur(f);
6397
  if (is_alpha(ch)) {
6398
    TRY(parse_identifier(f));
6399
  } else if (ch == '"') {
6400
    TRY(parse_string(f));
6401
  } else {
6402
    return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
6403
  }
6404
  return 0;
6405
}
6406
6407
/* pair = key ':' value */
6408
static int parse_pair(struct frozen *f) {
6409
  int current_path_len;
6410
  const char *tok;
6411
  skip_whitespaces(f);
6412
  tok = f->cur;
6413
  TRY(parse_key(f));
6414
  {
6415
    f->cur_name = *tok == '"' ? tok + 1 : tok;
6416
    f->cur_name_len = *tok == '"' ? f->cur - tok - 2 : f->cur - tok;
6417
    current_path_len = append_to_path(f, f->cur_name, f->cur_name_len);
6418
  }
6419
  TRY(test_and_skip(f, ':'));
6420
  TRY(parse_value(f));
6421
  truncate_path(f, current_path_len);
6422
  return 0;
6423
}
6424
6425
/* object = '{' pair { ',' pair } '}' */
6426
static int parse_object(struct frozen *f) {
6427
  CALL_BACK(f, JSON_TYPE_OBJECT_START, NULL, 0);
6428
  TRY(test_and_skip(f, '{'));
6429
  {
6430
    SET_STATE(f, f->cur - 1, ".", 1);
6431
    while (cur(f) != '}') {
6432
      TRY(parse_pair(f));
6433
      if (cur(f) == ',') f->cur++;
6434
    }
6435
    TRY(test_and_skip(f, '}'));
6436
    truncate_path(f, fstate.path_len);
6437
    CALL_BACK(f, JSON_TYPE_OBJECT_END, fstate.ptr, f->cur - fstate.ptr);
6438
  }
6439
  return 0;
6440
}
6441
6442
static int doit(struct frozen *f) {
6443
  if (f->cur == 0 || f->end < f->cur) return JSON_STRING_INVALID;
6444
  if (f->end == f->cur) return JSON_STRING_INCOMPLETE;
6445
  return parse_value(f);
6446
}
6447
6448
int json_escape(struct json_out *out, const char *p, size_t len) WEAK;
6449
int json_escape(struct json_out *out, const char *p, size_t len) {
6450
  size_t i, cl, n = 0;
6451
  const char *hex_digits = "0123456789abcdef";
6452
  const char *specials = "btnvfr";
6453
6454
  for (i = 0; i < len; i++) {
6455
    unsigned char ch = ((unsigned char *) p)[i];
6456
    if (ch == '"' || ch == '\\') {
6457
      n += out->printer(out, "\\", 1);
6458
      n += out->printer(out, p + i, 1);
6459
    } else if (ch >= '\b' && ch <= '\r') {
6460
      n += out->printer(out, "\\", 1);
6461
      n += out->printer(out, &specials[ch - '\b'], 1);
6462
    } else if (isprint(ch)) {
6463
      n += out->printer(out, p + i, 1);
6464
    } else if ((cl = get_utf8_char_len(ch)) == 1) {
6465
      n += out->printer(out, "\\u00", 4);
6466
      n += out->printer(out, &hex_digits[(ch >> 4) % 0xf], 1);
6467
      n += out->printer(out, &hex_digits[ch % 0xf], 1);
6468
    } else {
6469
      n += out->printer(out, p + i, cl);
6470
      i += cl - 1;
6471
    }
6472
  }
6473
6474
  return n;
6475
}
6476
6477
int json_printer_buf(struct json_out *out, const char *buf, size_t len) WEAK;
6478
int json_printer_buf(struct json_out *out, const char *buf, size_t len) {
6479
  size_t avail = out->u.buf.size - out->u.buf.len;
6480
  size_t n = len < avail ? len : avail;
6481
  memcpy(out->u.buf.buf + out->u.buf.len, buf, n);
6482
  out->u.buf.len += n;
6483
  if (out->u.buf.size > 0) {
6484
    size_t idx = out->u.buf.len;
6485
    if (idx >= out->u.buf.size) idx = out->u.buf.size - 1;
6486
    out->u.buf.buf[idx] = '\0';
6487
  }
6488
  return len;
6489
}
6490
6491
int json_printer_file(struct json_out *out, const char *buf, size_t len) WEAK;
6492
70
int json_printer_file(struct json_out *out, const char *buf, size_t len) {
6493
70
  return fwrite(buf, 1, len, out->u.fp);
6494
}
6495
6496
static int b64idx(int c) {
6497
  if (c < 26) {
6498
    return c + 'A';
6499
  } else if (c < 52) {
6500
    return c - 26 + 'a';
6501
  } else if (c < 62) {
6502
    return c - 52 + '0';
6503
  } else {
6504
    return c == 62 ? '+' : '/';
6505
  }
6506
}
6507
6508
static int b64rev(int c) {
6509
  if (c >= 'A' && c <= 'Z') {
6510
    return c - 'A';
6511
  } else if (c >= 'a' && c <= 'z') {
6512
    return c + 26 - 'a';
6513
  } else if (c >= '0' && c <= '9') {
6514
    return c + 52 - '0';
6515
  } else if (c == '+') {
6516
    return 62;
6517
  } else if (c == '/') {
6518
    return 63;
6519
  } else {
6520
    return 64;
6521
  }
6522
}
6523
6524
static unsigned char hexdec(const char *s) {
6525
#define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W')
6526
  int a = tolower(*(const unsigned char *) s);
6527
  int b = tolower(*(const unsigned char *) (s + 1));
6528
  return (HEXTOI(a) << 4) | HEXTOI(b);
6529
}
6530
6531
static int b64enc(struct json_out *out, const unsigned char *p, int n) {
6532
  char buf[4];
6533
  int i, len = 0;
6534
  for (i = 0; i < n; i += 3) {
6535
    int a = p[i], b = i + 1 < n ? p[i + 1] : 0, c = i + 2 < n ? p[i + 2] : 0;
6536
    buf[0] = b64idx(a >> 2);
6537
    buf[1] = b64idx((a & 3) << 4 | (b >> 4));
6538
    buf[2] = b64idx((b & 15) << 2 | (c >> 6));
6539
    buf[3] = b64idx(c & 63);
6540
    if (i + 1 >= n) buf[2] = '=';
6541
    if (i + 2 >= n) buf[3] = '=';
6542
    len += out->printer(out, buf, sizeof(buf));
6543
  }
6544
  return len;
6545
}
6546
6547
static int b64dec(const char *src, int n, char *dst) {
6548
  const char *end = src + n;
6549
  int len = 0;
6550
  while (src + 3 < end) {
6551
    int a = b64rev(src[0]), b = b64rev(src[1]), c = b64rev(src[2]),
6552
        d = b64rev(src[3]);
6553
    dst[len++] = (a << 2) | (b >> 4);
6554
    if (src[2] != '=') {
6555
      dst[len++] = (b << 4) | (c >> 2);
6556
      if (src[3] != '=') {
6557
        dst[len++] = (c << 6) | d;
6558
      }
6559
    }
6560
    src += 4;
6561
  }
6562
  return len;
6563
}
6564
6565
int json_vprintf(struct json_out *out, const char *fmt, va_list xap) WEAK;
6566
69
int json_vprintf(struct json_out *out, const char *fmt, va_list xap) {
6567
69
  int len = 0;
6568
69
  const char *quote = "\"", *null = "null";
6569
  va_list ap;
6570
69
  va_copy(ap, xap);
6571
6572
208
  while (*fmt != '\0') {
6573
70
    if (strchr(":, \r\n\t[]{}\"", *fmt) != NULL) {
6574
      len += out->printer(out, fmt, 1);
6575
      fmt++;
6576
70
    } else if (fmt[0] == '%') {
6577
      char buf[21];
6578
70
      size_t skip = 2;
6579
6580


70
      if (fmt[1] == 'l' && fmt[2] == 'l' && (fmt[3] == 'd' || fmt[3] == 'u')) {
6581
        int64_t val = va_arg(ap, int64_t);
6582
        const char *fmt2 = fmt[3] == 'u' ? "%" UINT64_FMT : "%" INT64_FMT;
6583
        snprintf(buf, sizeof(buf), fmt2, val);
6584
        len += out->printer(out, buf, strlen(buf));
6585
        skip += 2;
6586

70
      } else if (fmt[1] == 'z' && fmt[2] == 'u') {
6587
        size_t val = va_arg(ap, size_t);
6588
        snprintf(buf, sizeof(buf), "%lu", (unsigned long) val);
6589
        len += out->printer(out, buf, strlen(buf));
6590
        skip += 1;
6591
70
      } else if (fmt[1] == 'M') {
6592
        json_printf_callback_t f = va_arg(ap, json_printf_callback_t);
6593
        len += f(out, &ap);
6594
70
      } else if (fmt[1] == 'B') {
6595
        int val = va_arg(ap, int);
6596
        const char *str = val ? "true" : "false";
6597
        len += out->printer(out, str, strlen(str));
6598
70
      } else if (fmt[1] == 'H') {
6599
        const char *hex = "0123456789abcdef";
6600
        int i, n = va_arg(ap, int);
6601
        const unsigned char *p = va_arg(ap, const unsigned char *);
6602
        len += out->printer(out, quote, 1);
6603
        for (i = 0; i < n; i++) {
6604
          len += out->printer(out, &hex[(p[i] >> 4) & 0xf], 1);
6605
          len += out->printer(out, &hex[p[i] & 0xf], 1);
6606
        }
6607
        len += out->printer(out, quote, 1);
6608
70
      } else if (fmt[1] == 'V') {
6609
        const unsigned char *p = va_arg(ap, const unsigned char *);
6610
        int n = va_arg(ap, int);
6611
        len += out->printer(out, quote, 1);
6612
        len += b64enc(out, p, n);
6613
        len += out->printer(out, quote, 1);
6614

140
      } else if (fmt[1] == 'Q' ||
6615

70
                 (fmt[1] == '.' && fmt[2] == '*' && fmt[3] == 'Q')) {
6616
        size_t l = 0;
6617
        const char *p;
6618
6619
        if (fmt[1] == '.') {
6620
          l = (size_t) va_arg(ap, int);
6621
          skip += 2;
6622
        }
6623
        p = va_arg(ap, char *);
6624
6625
        if (p == NULL) {
6626
          len += out->printer(out, null, 4);
6627
        } else {
6628
          if (fmt[1] == 'Q') {
6629
            l = strlen(p);
6630
          }
6631
          len += out->printer(out, quote, 1);
6632
          len += json_escape(out, p, l);
6633
          len += out->printer(out, quote, 1);
6634
        }
6635
      } else {
6636
        /*
6637
         * we delegate printing to the system printf.
6638
         * The goal here is to delegate all modifiers parsing to the system
6639
         * printf, as you can see below we still have to parse the format
6640
         * types.
6641
         *
6642
         * Currently, %s with strings longer than 20 chars will require
6643
         * double-buffering (an auxiliary buffer will be allocated from heap).
6644
         * TODO(dfrank): reimplement %s and %.*s in order to avoid that.
6645
         */
6646
6647
70
        const char *end_of_format_specifier = "sdfFgGlhuIcx.*-0123456789";
6648
70
        int n = strspn(fmt + 1, end_of_format_specifier);
6649
70
        char *pbuf = buf;
6650
70
        int need_len, size = sizeof(buf);
6651
        char fmt2[20];
6652
        va_list ap_copy;
6653
140
        strncpy(fmt2, fmt,
6654
140
                n + 1 > (int) sizeof(fmt2) ? sizeof(fmt2) : (size_t) n + 1);
6655
70
        fmt2[n + 1] = '\0';
6656
6657
70
        va_copy(ap_copy, ap);
6658
70
        need_len = vsnprintf(pbuf, size, fmt2, ap_copy);
6659
70
        va_end(ap_copy);
6660
6661
70
        if (need_len < 0) {
6662
          /*
6663
           * Windows & eCos vsnprintf implementation return -1 on overflow
6664
           * instead of needed size.
6665
           */
6666
          pbuf = NULL;
6667
          while (need_len < 0) {
6668
            free(pbuf);
6669
            size *= 2;
6670
            if ((pbuf = (char *) malloc(size)) == NULL) break;
6671
            va_copy(ap_copy, ap);
6672
            need_len = vsnprintf(pbuf, size, fmt2, ap_copy);
6673
            va_end(ap_copy);
6674
          }
6675
70
        } else if (need_len >= (int) sizeof(buf)) {
6676
          /*
6677
           * resulting string doesn't fit into a stack-allocated buffer `buf`,
6678
           * so we need to allocate a new buffer from heap and use it
6679
           */
6680
          if ((pbuf = (char *) malloc(need_len + 1)) != NULL) {
6681
            va_copy(ap_copy, ap);
6682
            vsnprintf(pbuf, need_len + 1, fmt2, ap_copy);
6683
            va_end(ap_copy);
6684
          }
6685
        }
6686
70
        if (pbuf == NULL) {
6687
          buf[0] = '\0';
6688
          pbuf = buf;
6689
        }
6690
6691
        /*
6692
         * however we need to parse the type ourselves in order to advance
6693
         * the va_list by the correct amount; there is no portable way to
6694
         * inherit the advancement made by vprintf.
6695
         * 32-bit (linux or windows) passes va_list by value.
6696
         */
6697

70
        if ((n + 1 == strlen("%" PRId64) && strcmp(fmt2, "%" PRId64) == 0) ||
6698
            (n + 1 == strlen("%" PRIu64) && strcmp(fmt2, "%" PRIu64) == 0)) {
6699
1
          (void) va_arg(ap, int64_t);
6700
69
        } else if (strcmp(fmt2, "%.*s") == 0) {
6701
          (void) va_arg(ap, int);
6702
          (void) va_arg(ap, char *);
6703
        } else {
6704

69
          switch (fmt2[n]) {
6705
            case 'u':
6706
            case 'd':
6707
              (void) va_arg(ap, int);
6708
              break;
6709
            case 'g':
6710
            case 'f':
6711
2
              (void) va_arg(ap, double);
6712
2
              break;
6713
            case 'p':
6714
              (void) va_arg(ap, void *);
6715
              break;
6716
            default:
6717
              /* many types are promoted to int */
6718
67
              (void) va_arg(ap, int);
6719
          }
6720
        }
6721
6722
70
        len += out->printer(out, pbuf, strlen(pbuf));
6723
70
        skip = n + 1;
6724
6725
        /* If buffer was allocated from heap, free it */
6726
70
        if (pbuf != buf) {
6727
          free(pbuf);
6728
          pbuf = NULL;
6729
        }
6730
      }
6731
70
      fmt += skip;
6732
    } else if (*fmt == '_' || is_alpha(*fmt)) {
6733
      len += out->printer(out, quote, 1);
6734
      while (*fmt == '_' || is_alpha(*fmt) || is_digit(*fmt)) {
6735
        len += out->printer(out, fmt, 1);
6736
        fmt++;
6737
      }
6738
      len += out->printer(out, quote, 1);
6739
    } else {
6740
      len += out->printer(out, fmt, 1);
6741
      fmt++;
6742
    }
6743
  }
6744
69
  va_end(ap);
6745
6746
69
  return len;
6747
}
6748
6749
int json_printf(struct json_out *out, const char *fmt, ...) WEAK;
6750
69
int json_printf(struct json_out *out, const char *fmt, ...) {
6751
  int n;
6752
  va_list ap;
6753
69
  va_start(ap, fmt);
6754
69
  n = json_vprintf(out, fmt, ap);
6755
69
  va_end(ap);
6756
69
  return n;
6757
}
6758
6759
int json_printf_array(struct json_out *out, va_list *ap) WEAK;
6760
int json_printf_array(struct json_out *out, va_list *ap) {
6761
  int len = 0;
6762
  char *arr = va_arg(*ap, char *);
6763
  size_t i, arr_size = va_arg(*ap, size_t);
6764
  size_t elem_size = va_arg(*ap, size_t);
6765
  const char *fmt = va_arg(*ap, char *);
6766
  len += json_printf(out, "[", 1);
6767
  for (i = 0; arr != NULL && i < arr_size / elem_size; i++) {
6768
    union {
6769
      int64_t i;
6770
      double d;
6771
    } val;
6772
    memcpy(&val, arr + i * elem_size,
6773
           elem_size > sizeof(val) ? sizeof(val) : elem_size);
6774
    if (i > 0) len += json_printf(out, ", ");
6775
    if (strchr(fmt, 'f') != NULL) {
6776
      len += json_printf(out, fmt, val.d);
6777
    } else {
6778
      len += json_printf(out, fmt, val.i);
6779
    }
6780
  }
6781
  len += json_printf(out, "]", 1);
6782
  return len;
6783
}
6784
6785
#ifdef _WIN32
6786
int cs_win_vsnprintf(char *str, size_t size, const char *format,
6787
                     va_list ap) WEAK;
6788
int cs_win_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
6789
  int res = _vsnprintf(str, size, format, ap);
6790
  va_end(ap);
6791
  if (res >= size) {
6792
    str[size - 1] = '\0';
6793
  }
6794
  return res;
6795
}
6796
6797
int cs_win_snprintf(char *str, size_t size, const char *format, ...) WEAK;
6798
int cs_win_snprintf(char *str, size_t size, const char *format, ...) {
6799
  int res;
6800
  va_list ap;
6801
  va_start(ap, format);
6802
  res = vsnprintf(str, size, format, ap);
6803
  va_end(ap);
6804
  return res;
6805
}
6806
#endif /* _WIN32 */
6807
6808
int json_walk(const char *json_string, int json_string_length,
6809
              json_walk_callback_t callback, void *callback_data) WEAK;
6810
int json_walk(const char *json_string, int json_string_length,
6811
              json_walk_callback_t callback, void *callback_data) {
6812
  struct frozen frozen;
6813
6814
  memset(&frozen, 0, sizeof(frozen));
6815
  frozen.end = json_string + json_string_length;
6816
  frozen.cur = json_string;
6817
  frozen.callback_data = callback_data;
6818
  frozen.callback = callback;
6819
6820
  TRY(doit(&frozen));
6821
6822
  return frozen.cur - json_string;
6823
}
6824
6825
struct scan_array_info {
6826
  int found;
6827
  char path[JSON_MAX_PATH_LEN];
6828
  struct json_token *token;
6829
};
6830
6831
static void json_scanf_array_elem_cb(void *callback_data, const char *name,
6832
                                     size_t name_len, const char *path,
6833
                                     const struct json_token *token) {
6834
  struct scan_array_info *info = (struct scan_array_info *) callback_data;
6835
6836
  (void) name;
6837
  (void) name_len;
6838
6839
  if (strcmp(path, info->path) == 0) {
6840
    *info->token = *token;
6841
    info->found = 1;
6842
  }
6843
}
6844
6845
int json_scanf_array_elem(const char *s, int len, const char *path, int idx,
6846
                          struct json_token *token) WEAK;
6847
int json_scanf_array_elem(const char *s, int len, const char *path, int idx,
6848
                          struct json_token *token) {
6849
  struct scan_array_info info;
6850
  info.token = token;
6851
  info.found = 0;
6852
  memset(token, 0, sizeof(*token));
6853
  snprintf(info.path, sizeof(info.path), "%s[%d]", path, idx);
6854
  json_walk(s, len, json_scanf_array_elem_cb, &info);
6855
  return info.found ? token->len : -1;
6856
}
6857
6858
struct json_scanf_info {
6859
  int num_conversions;
6860
  char *path;
6861
  const char *fmt;
6862
  void *target;
6863
  void *user_data;
6864
  int type;
6865
};
6866
6867
int json_unescape(const char *src, int slen, char *dst, int dlen) WEAK;
6868
int json_unescape(const char *src, int slen, char *dst, int dlen) {
6869
  char *send = (char *) src + slen, *dend = dst + dlen, *orig_dst = dst, *p;
6870
  const char *esc1 = "\"\\/bfnrt", *esc2 = "\"\\/\b\f\n\r\t";
6871
6872
  while (src < send) {
6873
    if (*src == '\\') {
6874
      if (++src >= send) return JSON_STRING_INCOMPLETE;
6875
      if (*src == 'u') {
6876
        /* TODO(lsm): \uXXXX escapes drag utf8 lib... Do it at some stage */
6877
        return JSON_STRING_INVALID;
6878
      } else if ((p = (char *) strchr(esc1, *src)) != NULL) {
6879
        if (dst < dend) *dst = esc2[p - esc1];
6880
      } else {
6881
        return JSON_STRING_INVALID;
6882
      }
6883
    } else {
6884
      if (dst < dend) *dst = *src;
6885
    }
6886
    dst++;
6887
    src++;
6888
  }
6889
6890
  return dst - orig_dst;
6891
}
6892
6893
static void json_scanf_cb(void *callback_data, const char *name,
6894
                          size_t name_len, const char *path,
6895
                          const struct json_token *token) {
6896
  struct json_scanf_info *info = (struct json_scanf_info *) callback_data;
6897
  char buf[32]; /* Must be enough to hold numbers */
6898
6899
  (void) name;
6900
  (void) name_len;
6901
6902
  if (strcmp(path, info->path) != 0) {
6903
    /* It's not the path we're looking for, so, just ignore this callback */
6904
    return;
6905
  }
6906
6907
  if (token->ptr == NULL) {
6908
    /*
6909
     * We're not interested here in the events for which we have no value;
6910
     * namely, JSON_TYPE_OBJECT_START and JSON_TYPE_ARRAY_START
6911
     */
6912
    return;
6913
  }
6914
6915
  switch (info->type) {
6916
    case 'B':
6917
      info->num_conversions++;
6918
      switch (sizeof(bool)) {
6919
        case sizeof(char):
6920
          *(char *) info->target = (token->type == JSON_TYPE_TRUE ? 1 : 0);
6921
          break;
6922
        case sizeof(int):
6923
          *(int *) info->target = (token->type == JSON_TYPE_TRUE ? 1 : 0);
6924
          break;
6925
        default:
6926
          /* should never be here */
6927
          abort();
6928
      }
6929
      break;
6930
    case 'M': {
6931
      union {
6932
        void *p;
6933
        json_scanner_t f;
6934
      } u = {info->target};
6935
      info->num_conversions++;
6936
      u.f(token->ptr, token->len, info->user_data);
6937
      break;
6938
    }
6939
    case 'Q': {
6940
      char **dst = (char **) info->target;
6941
      if (token->type == JSON_TYPE_NULL) {
6942
        *dst = NULL;
6943
      } else {
6944
        int unescaped_len = json_unescape(token->ptr, token->len, NULL, 0);
6945
        if (unescaped_len >= 0 &&
6946
            (*dst = (char *) malloc(unescaped_len + 1)) != NULL) {
6947
          info->num_conversions++;
6948
          if (json_unescape(token->ptr, token->len, *dst, unescaped_len) ==
6949
              unescaped_len) {
6950
            (*dst)[unescaped_len] = '\0';
6951
          } else {
6952
            free(*dst);
6953
            *dst = NULL;
6954
          }
6955
        }
6956
      }
6957
      break;
6958
    }
6959
    case 'H': {
6960
      char **dst = (char **) info->user_data;
6961
      int i, len = token->len / 2;
6962
      *(int *) info->target = len;
6963
      if ((*dst = (char *) malloc(len + 1)) != NULL) {
6964
        for (i = 0; i < len; i++) {
6965
          (*dst)[i] = hexdec(token->ptr + 2 * i);
6966
        }
6967
        (*dst)[len] = '\0';
6968
        info->num_conversions++;
6969
      }
6970
      break;
6971
    }
6972
    case 'V': {
6973
      char **dst = (char **) info->target;
6974
      int len = token->len * 4 / 3 + 2;
6975
      if ((*dst = (char *) malloc(len + 1)) != NULL) {
6976
        int n = b64dec(token->ptr, token->len, *dst);
6977
        (*dst)[n] = '\0';
6978
        *(int *) info->user_data = n;
6979
        info->num_conversions++;
6980
      }
6981
      break;
6982
    }
6983
    case 'T':
6984
      info->num_conversions++;
6985
      *(struct json_token *) info->target = *token;
6986
      break;
6987
    default:
6988
      /* Before scanf, copy into tmp buffer in order to 0-terminate it */
6989
      if (token->len < (int) sizeof(buf)) {
6990
        memcpy(buf, token->ptr, token->len);
6991
        buf[token->len] = '\0';
6992
        info->num_conversions += sscanf(buf, info->fmt, info->target);
6993
      }
6994
      break;
6995
  }
6996
}
6997
6998
int json_vscanf(const char *s, int len, const char *fmt, va_list ap) WEAK;
6999
int json_vscanf(const char *s, int len, const char *fmt, va_list ap) {
7000
  char path[JSON_MAX_PATH_LEN] = "", fmtbuf[20];
7001
  int i = 0;
7002
  char *p = NULL;
7003
  struct json_scanf_info info = {0, path, fmtbuf, NULL, NULL, 0};
7004
7005
  while (fmt[i] != '\0') {
7006
    if (fmt[i] == '{') {
7007
      strcat(path, ".");
7008
      i++;
7009
    } else if (fmt[i] == '}') {
7010
      if ((p = strrchr(path, '.')) != NULL) *p = '\0';
7011
      i++;
7012
    } else if (fmt[i] == '%') {
7013
      info.target = va_arg(ap, void *);
7014
      info.type = fmt[i + 1];
7015
      switch (fmt[i + 1]) {
7016
        case 'M':
7017
        case 'V':
7018
        case 'H':
7019
          info.user_data = va_arg(ap, void *);
7020
        /* FALLTHROUGH */
7021
        case 'B':
7022
        case 'Q':
7023
        case 'T':
7024
          i += 2;
7025
          break;
7026
        default: {
7027
          const char *delims = ", \t\r\n]}";
7028
          int conv_len = strcspn(fmt + i + 1, delims) + 1;
7029
          snprintf(fmtbuf, sizeof(fmtbuf), "%.*s", conv_len, fmt + i);
7030
          i += conv_len;
7031
          i += strspn(fmt + i, delims);
7032
          break;
7033
        }
7034
      }
7035
      json_walk(s, len, json_scanf_cb, &info);
7036
    } else if (is_alpha(fmt[i]) || get_utf8_char_len(fmt[i]) > 1) {
7037
      const char *delims = ": \r\n\t";
7038
      int key_len = strcspn(&fmt[i], delims);
7039
      if ((p = strrchr(path, '.')) != NULL) p[1] = '\0';
7040
      sprintf(path + strlen(path), "%.*s", key_len, &fmt[i]);
7041
      i += key_len + strspn(fmt + i + key_len, delims);
7042
    } else {
7043
      i++;
7044
    }
7045
  }
7046
  return info.num_conversions;
7047
}
7048
7049
int json_scanf(const char *str, int len, const char *fmt, ...) WEAK;
7050
int json_scanf(const char *str, int len, const char *fmt, ...) {
7051
  int result;
7052
  va_list ap;
7053
  va_start(ap, fmt);
7054
  result = json_vscanf(str, len, fmt, ap);
7055
  va_end(ap);
7056
  return result;
7057
}
7058
7059
int json_vfprintf(const char *file_name, const char *fmt, va_list ap) WEAK;
7060
int json_vfprintf(const char *file_name, const char *fmt, va_list ap) {
7061
  int res = -1;
7062
  FILE *fp = fopen(file_name, "wb");
7063
  if (fp != NULL) {
7064
    struct json_out out = JSON_OUT_FILE(fp);
7065
    res = json_vprintf(&out, fmt, ap);
7066
    fputc('\n', fp);
7067
    fclose(fp);
7068
  }
7069
  return res;
7070
}
7071
7072
int json_fprintf(const char *file_name, const char *fmt, ...) WEAK;
7073
int json_fprintf(const char *file_name, const char *fmt, ...) {
7074
  int result;
7075
  va_list ap;
7076
  va_start(ap, fmt);
7077
  result = json_vfprintf(file_name, fmt, ap);
7078
  va_end(ap);
7079
  return result;
7080
}
7081
7082
char *json_fread(const char *path) WEAK;
7083
char *json_fread(const char *path) {
7084
  FILE *fp;
7085
  char *data = NULL;
7086
  if ((fp = fopen(path, "rb")) == NULL) {
7087
  } else if (fseek(fp, 0, SEEK_END) != 0) {
7088
    fclose(fp);
7089
  } else {
7090
    long size = ftell(fp);
7091
    if (size > 0 && (data = (char *) malloc(size + 1)) != NULL) {
7092
      fseek(fp, 0, SEEK_SET); /* Some platforms might not have rewind(), Oo */
7093
      if (fread(data, 1, size, fp) != (size_t) size) {
7094
        free(data);
7095
        data = NULL;
7096
      } else {
7097
        data[size] = '\0';
7098
      }
7099
    }
7100
    fclose(fp);
7101
  }
7102
  return data;
7103
}
7104
7105
struct json_setf_data {
7106
  const char *json_path;
7107
  const char *base; /* Pointer to the source JSON string */
7108
  int matched;      /* Matched part of json_path */
7109
  int pos;          /* Offset of the mutated value begin */
7110
  int end;          /* Offset of the mutated value end */
7111
  int prev;         /* Offset of the previous token end */
7112
};
7113
7114
static int get_matched_prefix_len(const char *s1, const char *s2) {
7115
  int i = 0;
7116
  while (s1[i] && s2[i] && s1[i] == s2[i]) i++;
7117
  return i;
7118
}
7119
7120
static void json_vsetf_cb(void *userdata, const char *name, size_t name_len,
7121
                          const char *path, const struct json_token *t) {
7122
  struct json_setf_data *data = (struct json_setf_data *) userdata;
7123
  int off, len = get_matched_prefix_len(path, data->json_path);
7124
  if (t->ptr == NULL) return;
7125
  off = t->ptr - data->base;
7126
  // printf("--%d %s %d\n", t->type, path, off);
7127
  if (len > data->matched) data->matched = len;
7128
7129
  /*
7130
   * If there is no exact path match, set the mutation position to tbe end
7131
   * of the object or array
7132
   */
7133
  if (len < data->matched && data->pos == 0 &&
7134
      (t->type == JSON_TYPE_OBJECT_END || t->type == JSON_TYPE_ARRAY_END)) {
7135
    data->pos = data->end = data->prev;
7136
  }
7137
7138
  /* Exact path match. Set mutation position to the value of this token */
7139
  if (strcmp(path, data->json_path) == 0 && t->type != JSON_TYPE_OBJECT_START &&
7140
      t->type != JSON_TYPE_ARRAY_START) {
7141
    data->pos = off;
7142
    data->end = off + t->len;
7143
  }
7144
7145
  /*
7146
   * For deletion, we need to know where the previous value ends, because
7147
   * we don't know where matched value key starts.
7148
   * When the mutation position is not yet set, remember each value end.
7149
   * When the mutation position is already set, but it is at the beginning
7150
   * of the object/array, we catch the end of the object/array and see
7151
   * whether the object/array start is closer then previously stored prev.
7152
   */
7153
  if (data->pos == 0) {
7154
    data->prev = off + t->len; /* pos is not yet set */
7155
  } else if ((t->ptr[0] == '[' || t->ptr[0] == '{') && off + 1 < data->pos &&
7156
             off + 1 > data->prev) {
7157
    data->prev = off + 1;
7158
  }
7159
  (void) name;
7160
  (void) name_len;
7161
}
7162
7163
int json_vsetf(const char *s, int len, struct json_out *out,
7164
               const char *json_path, const char *json_fmt, va_list ap) WEAK;
7165
int json_vsetf(const char *s, int len, struct json_out *out,
7166
               const char *json_path, const char *json_fmt, va_list ap) {
7167
  struct json_setf_data data;
7168
  memset(&data, 0, sizeof(data));
7169
  data.json_path = json_path;
7170
  data.base = s;
7171
  data.end = len;
7172
  // printf("S:[%.*s] %s %p\n", len, s, json_path, json_fmt);
7173
  json_walk(s, len, json_vsetf_cb, &data);
7174
  // printf("-> %d %d %d\n", data.prev, data.pos, data.end);
7175
  if (json_fmt == NULL) {
7176
    /* Deletion codepath */
7177
    json_printf(out, "%.*s", data.prev, s);
7178
    /* Trim comma after the value that begins at object/array start */
7179
    if (s[data.prev - 1] == '{' || s[data.prev - 1] == '[') {
7180
      int i = data.end;
7181
      while (i < len && is_space(s[i])) i++;
7182
      if (s[i] == ',') data.end = i + 1; /* Point after comma */
7183
    }
7184
    json_printf(out, "%.*s", len - data.end, s + data.end);
7185
  } else {
7186
    /* Modification codepath */
7187
    int n, off = data.matched, depth = 0;
7188
7189
    /* Print the unchanged beginning */
7190
    json_printf(out, "%.*s", data.pos, s);
7191
7192
    /* Add missing keys */
7193
    while ((n = strcspn(&json_path[off], ".[")) > 0) {
7194
      if (s[data.prev - 1] != '{' && s[data.prev - 1] != '[' && depth == 0) {
7195
        json_printf(out, ",");
7196
      }
7197
      if (off > 0 && json_path[off - 1] != '.') break;
7198
      json_printf(out, "%.*Q:", 1, json_path + off);
7199
      off += n;
7200
      if (json_path[off] != '\0') {
7201
        json_printf(out, "%c", json_path[off] == '.' ? '{' : '[');
7202
        depth++;
7203
        off++;
7204
      }
7205
    }
7206
    /* Print the new value */
7207
    json_vprintf(out, json_fmt, ap);
7208
7209
    /* Close brackets/braces of the added missing keys */
7210
    for (; off > data.matched; off--) {
7211
      int ch = json_path[off];
7212
      const char *p = ch == '.' ? "}" : ch == '[' ? "]" : "";
7213
      json_printf(out, "%s", p);
7214
    }
7215
7216
    /* Print the rest of the unchanged string */
7217
    json_printf(out, "%.*s", len - data.end, s + data.end);
7218
  }
7219
  return data.end > data.pos ? 1 : 0;
7220
}
7221
7222
int json_setf(const char *s, int len, struct json_out *out,
7223
              const char *json_path, const char *json_fmt, ...) WEAK;
7224
int json_setf(const char *s, int len, struct json_out *out,
7225
              const char *json_path, const char *json_fmt, ...) {
7226
  int result;
7227
  va_list ap;
7228
  va_start(ap, json_fmt);
7229
  result = json_vsetf(s, len, out, json_path, json_fmt, ap);
7230
  va_end(ap);
7231
  return result;
7232
}
7233
7234
struct prettify_data {
7235
  struct json_out *out;
7236
  int level;
7237
  int last_token;
7238
};
7239
7240
static void indent(struct json_out *out, int level) {
7241
  while (level-- > 0) out->printer(out, "  ", 2);
7242
}
7243
7244
static void print_key(struct prettify_data *pd, const char *path,
7245
                      const char *name, int name_len) {
7246
  if (pd->last_token != JSON_TYPE_INVALID &&
7247
      pd->last_token != JSON_TYPE_ARRAY_START &&
7248
      pd->last_token != JSON_TYPE_OBJECT_START) {
7249
    pd->out->printer(pd->out, ",", 1);
7250
  }
7251
  if (path[0] != '\0') pd->out->printer(pd->out, "\n", 1);
7252
  indent(pd->out, pd->level);
7253
  if (path[0] != '\0' && path[strlen(path) - 1] != ']') {
7254
    pd->out->printer(pd->out, "\"", 1);
7255
    pd->out->printer(pd->out, name, (int) name_len);
7256
    pd->out->printer(pd->out, "\"", 1);
7257
    pd->out->printer(pd->out, ": ", 2);
7258
  }
7259
}
7260
7261
static void prettify_cb(void *userdata, const char *name, size_t name_len,
7262
                        const char *path, const struct json_token *t) {
7263
  struct prettify_data *pd = (struct prettify_data *) userdata;
7264
  switch (t->type) {
7265
    case JSON_TYPE_OBJECT_START:
7266
    case JSON_TYPE_ARRAY_START:
7267
      print_key(pd, path, name, name_len);
7268
      pd->out->printer(pd->out, t->type == JSON_TYPE_ARRAY_START ? "[" : "{",
7269
                       1);
7270
      pd->level++;
7271
      break;
7272
    case JSON_TYPE_OBJECT_END:
7273
    case JSON_TYPE_ARRAY_END:
7274
      pd->level--;
7275
      if (pd->last_token != JSON_TYPE_INVALID &&
7276
          pd->last_token != JSON_TYPE_ARRAY_START &&
7277
          pd->last_token != JSON_TYPE_OBJECT_START) {
7278
        pd->out->printer(pd->out, "\n", 1);
7279
        indent(pd->out, pd->level);
7280
      }
7281
      pd->out->printer(pd->out, t->type == JSON_TYPE_ARRAY_END ? "]" : "}", 1);
7282
      break;
7283
    case JSON_TYPE_NUMBER:
7284
    case JSON_TYPE_NULL:
7285
    case JSON_TYPE_TRUE:
7286
    case JSON_TYPE_FALSE:
7287
    case JSON_TYPE_STRING:
7288
      print_key(pd, path, name, name_len);
7289
      if (t->type == JSON_TYPE_STRING) pd->out->printer(pd->out, "\"", 1);
7290
      pd->out->printer(pd->out, t->ptr, t->len);
7291
      if (t->type == JSON_TYPE_STRING) pd->out->printer(pd->out, "\"", 1);
7292
      break;
7293
    default:
7294
      break;
7295
  }
7296
  pd->last_token = t->type;
7297
}
7298
7299
int json_prettify(const char *s, int len, struct json_out *out) WEAK;
7300
int json_prettify(const char *s, int len, struct json_out *out) {
7301
  struct prettify_data pd = {out, 0, JSON_TYPE_INVALID};
7302
  return json_walk(s, len, prettify_cb, &pd);
7303
}
7304
7305
int json_prettify_file(const char *file_name) WEAK;
7306
int json_prettify_file(const char *file_name) {
7307
  int res = -1;
7308
  char *s = json_fread(file_name);
7309
  FILE *fp;
7310
  if (s != NULL && (fp = fopen(file_name, "wb")) != NULL) {
7311
    struct json_out out = JSON_OUT_FILE(fp);
7312
    res = json_prettify(s, strlen(s), &out);
7313
    if (res < 0) {
7314
      /* On error, restore the old content */
7315
      fclose(fp);
7316
      fp = fopen(file_name, "wb");
7317
      fseek(fp, 0, SEEK_SET);
7318
      fwrite(s, 1, strlen(s), fp);
7319
    } else {
7320
      fputc('\n', fp);
7321
    }
7322
    fclose(fp);
7323
  }
7324
  free(s);
7325
  return res;
7326
}
7327
7328
struct next_data {
7329
  void *handle;            // Passed handle. Changed if a next entry is found
7330
  const char *path;        // Path to the iterated object/array
7331
  int path_len;            // Path length - optimisation
7332
  int found;               // Non-0 if found the next entry
7333
  struct json_token *key;  // Object's key
7334
  struct json_token *val;  // Object's value
7335
  int *idx;                // Array index
7336
};
7337
7338
static void next_set_key(struct next_data *d, const char *name, int name_len,
7339
                         int is_array) {
7340
  if (is_array) {
7341
    /* Array. Set index and reset key  */
7342
    if (d->key != NULL) {
7343
      d->key->len = 0;
7344
      d->key->ptr = NULL;
7345
    }
7346
    if (d->idx != NULL) *d->idx = atoi(name);
7347
  } else {
7348
    /* Object. Set key and make index -1 */
7349
    if (d->key != NULL) {
7350
      d->key->ptr = name;
7351
      d->key->len = name_len;
7352
    }
7353
    if (d->idx != NULL) *d->idx = -1;
7354
  }
7355
}
7356
7357
static void next_cb(void *userdata, const char *name, size_t name_len,
7358
                    const char *path, const struct json_token *t) {
7359
  struct next_data *d = (struct next_data *) userdata;
7360
  const char *p = path + d->path_len;
7361
  if (d->found) return;
7362
  if (d->path_len >= (int) strlen(path)) return;
7363
  if (strncmp(d->path, path, d->path_len) != 0) return;
7364
  if (strchr(p + 1, '.') != NULL) return; /* More nested objects - skip */
7365
  if (strchr(p + 1, '[') != NULL) return; /* Ditto for arrays */
7366
  // {OBJECT,ARRAY}_END types do not pass name, _START does. Save key.
7367
  if (t->type == JSON_TYPE_OBJECT_START || t->type == JSON_TYPE_ARRAY_START) {
7368
    // printf("SAV %s %d %p\n", path, t->type, t->ptr);
7369
    next_set_key(d, name, name_len, p[0] == '[');
7370
  } else if (d->handle == NULL || d->handle < (void *) t->ptr) {
7371
    // printf("END %s %d %p\n", path, t->type, t->ptr);
7372
    if (t->type != JSON_TYPE_OBJECT_END && t->type != JSON_TYPE_ARRAY_END) {
7373
      next_set_key(d, name, name_len, p[0] == '[');
7374
    }
7375
    if (d->val != NULL) *d->val = *t;
7376
    d->handle = (void *) t->ptr;
7377
    d->found = 1;
7378
  }
7379
}
7380
7381
static void *json_next(const char *s, int len, void *handle, const char *path,
7382
                       struct json_token *key, struct json_token *val, int *i) {
7383
  struct json_token tmpval, *v = val == NULL ? &tmpval : val;
7384
  struct json_token tmpkey, *k = key == NULL ? &tmpkey : key;
7385
  int tmpidx, *pidx = i == NULL ? &tmpidx : i;
7386
  struct next_data data = {handle, path, strlen(path), 0, k, v, pidx};
7387
  json_walk(s, len, next_cb, &data);
7388
  return data.found ? data.handle : NULL;
7389
}
7390
7391
void *json_next_key(const char *s, int len, void *handle, const char *path,
7392
                    struct json_token *key, struct json_token *val) WEAK;
7393
void *json_next_key(const char *s, int len, void *handle, const char *path,
7394
                    struct json_token *key, struct json_token *val) {
7395
  return json_next(s, len, handle, path, key, val, NULL);
7396
}
7397
7398
void *json_next_elem(const char *s, int len, void *handle, const char *path,
7399
                     int *idx, struct json_token *val) WEAK;
7400
void *json_next_elem(const char *s, int len, void *handle, const char *path,
7401
                     int *idx, struct json_token *val) {
7402
  return json_next(s, len, handle, path, NULL, val, idx);
7403
}
7404
7405
static int json_sprinter(struct json_out *out, const char *str, size_t len) {
7406
  size_t old_len = out->u.buf.buf == NULL ? 0 : strlen(out->u.buf.buf);
7407
  size_t new_len = len + old_len;
7408
  char *p = (char *) realloc(out->u.buf.buf, new_len + 1);
7409
  if (p != NULL) {
7410
    memcpy(p + old_len, str, len);
7411
    p[new_len] = '\0';
7412
    out->u.buf.buf = p;
7413
  }
7414
  return len;
7415
}
7416
7417
char *json_vasprintf(const char *fmt, va_list ap) WEAK;
7418
char *json_vasprintf(const char *fmt, va_list ap) {
7419
  struct json_out out;
7420
  memset(&out, 0, sizeof(out));
7421
  out.printer = json_sprinter;
7422
  json_vprintf(&out, fmt, ap);
7423
  return out.u.buf.buf;
7424
}
7425
7426
char *json_asprintf(const char *fmt, ...) WEAK;
7427
char *json_asprintf(const char *fmt, ...) {
7428
  char *result = NULL;
7429
  va_list ap;
7430
  va_start(ap, fmt);
7431
  result = json_vasprintf(fmt, ap);
7432
  va_end(ap);
7433
  return result;
7434
}
7435
#ifdef MJS_MODULE_LINES
7436
#line 1 "mjs/src/ffi/ffi.c"
7437
#endif
7438
/*
7439
 * Copyright (c) 2016 Cesanta Software Limited
7440
 * All rights reserved
7441
 */
7442
7443
/* Amalgamated: #include "mjs/src/ffi/ffi.h" */
7444
7445
#define IS_W(arg) ((arg).ctype == FFI_CTYPE_WORD)
7446
#define IS_D(arg) ((arg).ctype == FFI_CTYPE_DOUBLE)
7447
#define IS_F(arg) ((arg).ctype == FFI_CTYPE_FLOAT)
7448
7449
#define W(arg) ((ffi_word_t)(arg).v.i)
7450
#define D(arg) ((arg).v.d)
7451
#define F(arg) ((arg).v.f)
7452
7453
void ffi_set_word(struct ffi_arg *arg, ffi_word_t v) {
7454
  arg->ctype = FFI_CTYPE_WORD;
7455
  arg->v.i = v;
7456
}
7457
7458
void ffi_set_bool(struct ffi_arg *arg, bool v) {
7459
  arg->ctype = FFI_CTYPE_BOOL;
7460
  arg->v.i = v;
7461
}
7462
7463
void ffi_set_ptr(struct ffi_arg *arg, void *v) {
7464
  ffi_set_word(arg, (ffi_word_t) v);
7465
}
7466
7467
void ffi_set_double(struct ffi_arg *arg, double v) {
7468
  arg->ctype = FFI_CTYPE_DOUBLE;
7469
  arg->v.d = v;
7470
}
7471
7472
void ffi_set_float(struct ffi_arg *arg, float v) {
7473
  arg->ctype = FFI_CTYPE_FLOAT;
7474
  arg->v.f = v;
7475
}
7476
7477
/*
7478
 * The ARM ABI uses only 4 32-bit registers for paramter passing.
7479
 * Xtensa call0 calling-convention (as used by Espressif) has 6.
7480
 *
7481
 * Focusing only on implementing FFI with registers means we can simplify a lot.
7482
 *
7483
 * ARM has some quasi-alignment rules when mixing double and integers as
7484
 * arguments. Only:
7485
 *   a) double, int32_t, int32_t
7486
 *   b) int32_t, double
7487
 * would fit in 4 registers. (the same goes for uint64_t).
7488
 *
7489
 * In order to simplify further, when a double-width argument is present, we
7490
 * allow only two arguments.
7491
 */
7492
7493
/*
7494
 * We need to support x86_64 in order to support local tests.
7495
 * x86_64 has more and wider registers, but unlike the two main
7496
 * embedded platforms we target it has a separate register file for
7497
 * integer values and for floating point values (both for passing args and
7498
 * return values). E.g. if a double value is passed as a second argument
7499
 * it gets passed in the first available floating point register.
7500
 *
7501
 * I.e, the compiler generates exactly the same code for:
7502
 *
7503
 * void foo(int a, double b) {...}
7504
 *
7505
 * and
7506
 *
7507
 * void foo(double b, int a) {...}
7508
 *
7509
 *
7510
 */
7511
7512
typedef ffi_word_t (*w4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t);
7513
typedef ffi_word_t (*w5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t,
7514
                            ffi_word_t);
7515
typedef ffi_word_t (*w6w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t,
7516
                            ffi_word_t, ffi_word_t);
7517
7518
typedef ffi_word_t (*wdw_t)(double, ffi_word_t);
7519
typedef ffi_word_t (*wwd_t)(ffi_word_t, double);
7520
typedef ffi_word_t (*wdd_t)(double, double);
7521
7522
typedef ffi_word_t (*wwwd_t)(ffi_word_t, ffi_word_t, double);
7523
typedef ffi_word_t (*wwdw_t)(ffi_word_t, double, ffi_word_t);
7524
typedef ffi_word_t (*wwdd_t)(ffi_word_t, double, double);
7525
typedef ffi_word_t (*wdww_t)(double, ffi_word_t, ffi_word_t);
7526
typedef ffi_word_t (*wdwd_t)(double, ffi_word_t, double);
7527
typedef ffi_word_t (*wddw_t)(double, double, ffi_word_t);
7528
typedef ffi_word_t (*wddd_t)(double, double, double);
7529
7530
typedef ffi_word_t (*wfw_t)(float, ffi_word_t);
7531
typedef ffi_word_t (*wwf_t)(ffi_word_t, float);
7532
typedef ffi_word_t (*wff_t)(float, float);
7533
7534
typedef ffi_word_t (*wwwf_t)(ffi_word_t, ffi_word_t, float);
7535
typedef ffi_word_t (*wwfw_t)(ffi_word_t, float, ffi_word_t);
7536
typedef ffi_word_t (*wwff_t)(ffi_word_t, float, float);
7537
typedef ffi_word_t (*wfww_t)(float, ffi_word_t, ffi_word_t);
7538
typedef ffi_word_t (*wfwf_t)(float, ffi_word_t, float);
7539
typedef ffi_word_t (*wffw_t)(float, float, ffi_word_t);
7540
typedef ffi_word_t (*wfff_t)(float, float, float);
7541
7542
typedef bool (*b4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t);
7543
typedef bool (*b5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t,
7544
                      ffi_word_t);
7545
typedef bool (*b6w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t,
7546
                      ffi_word_t, ffi_word_t);
7547
typedef bool (*bdw_t)(double, ffi_word_t);
7548
typedef bool (*bwd_t)(ffi_word_t, double);
7549
typedef bool (*bdd_t)(double, double);
7550
7551
typedef bool (*bwwd_t)(ffi_word_t, ffi_word_t, double);
7552
typedef bool (*bwdw_t)(ffi_word_t, double, ffi_word_t);
7553
typedef bool (*bwdd_t)(ffi_word_t, double, double);
7554
typedef bool (*bdww_t)(double, ffi_word_t, ffi_word_t);
7555
typedef bool (*bdwd_t)(double, ffi_word_t, double);
7556
typedef bool (*bddw_t)(double, double, ffi_word_t);
7557
typedef bool (*bddd_t)(double, double, double);
7558
7559
typedef bool (*bfw_t)(float, ffi_word_t);
7560
typedef bool (*bwf_t)(ffi_word_t, float);
7561
typedef bool (*bff_t)(float, float);
7562
7563
typedef bool (*bwwf_t)(ffi_word_t, ffi_word_t, float);
7564
typedef bool (*bwfw_t)(ffi_word_t, float, ffi_word_t);
7565
typedef bool (*bwff_t)(ffi_word_t, float, float);
7566
typedef bool (*bfww_t)(float, ffi_word_t, ffi_word_t);
7567
typedef bool (*bfwf_t)(float, ffi_word_t, float);
7568
typedef bool (*bffw_t)(float, float, ffi_word_t);
7569
typedef bool (*bfff_t)(float, float, float);
7570
7571
typedef double (*d4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t);
7572
typedef double (*d5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t,
7573
                        ffi_word_t);
7574
typedef double (*d6w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t,
7575
                        ffi_word_t, ffi_word_t);
7576
typedef double (*ddw_t)(double, ffi_word_t);
7577
typedef double (*dwd_t)(ffi_word_t, double);
7578
typedef double (*ddd_t)(double, double);
7579
7580
typedef double (*dwwd_t)(ffi_word_t, ffi_word_t, double);
7581
typedef double (*dwdw_t)(ffi_word_t, double, ffi_word_t);
7582
typedef double (*dwdd_t)(ffi_word_t, double, double);
7583
typedef double (*ddww_t)(double, ffi_word_t, ffi_word_t);
7584
typedef double (*ddwd_t)(double, ffi_word_t, double);
7585
typedef double (*dddw_t)(double, double, ffi_word_t);
7586
typedef double (*dddd_t)(double, double, double);
7587
7588
typedef float (*f4w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t);
7589
typedef float (*f5w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t,
7590
                       ffi_word_t);
7591
typedef float (*f6w_t)(ffi_word_t, ffi_word_t, ffi_word_t, ffi_word_t,
7592
                       ffi_word_t, ffi_word_t);
7593
typedef float (*ffw_t)(float, ffi_word_t);
7594
typedef float (*fwf_t)(ffi_word_t, float);
7595
typedef float (*fff_t)(float, float);
7596
7597
typedef float (*fwwf_t)(ffi_word_t, ffi_word_t, float);
7598
typedef float (*fwfw_t)(ffi_word_t, float, ffi_word_t);
7599
typedef float (*fwff_t)(ffi_word_t, float, float);
7600
typedef float (*ffww_t)(float, ffi_word_t, ffi_word_t);
7601
typedef float (*ffwf_t)(float, ffi_word_t, float);
7602
typedef float (*fffw_t)(float, float, ffi_word_t);
7603
typedef float (*ffff_t)(float, float, float);
7604
7605
int ffi_call(ffi_fn_t *func, int nargs, struct ffi_arg *res,
7606
             struct ffi_arg *args) {
7607
  int i, doubles = 0, floats = 0;
7608
7609
  if (nargs > 6) return -1;
7610
  for (i = 0; i < nargs; i++) {
7611
    doubles += (IS_D(args[i]));
7612
    floats += (IS_F(args[i]));
7613
  }
7614
7615
  /* Doubles and floats are not supported together atm */
7616
  if (doubles > 0 && floats > 0) {
7617
    return -1;
7618
  }
7619
7620
  switch (res->ctype) {
7621
    case FFI_CTYPE_WORD: { /* {{{ */
7622
      ffi_word_t r;
7623
      if (doubles == 0) {
7624
        if (floats == 0) {
7625
          /*
7626
           * No double and no float args: we currently support up to 6
7627
           * word-sized arguments
7628
           */
7629
          if (nargs <= 4) {
7630
            w4w_t f = (w4w_t) func;
7631
            r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]));
7632
          } else if (nargs == 5) {
7633
            w5w_t f = (w5w_t) func;
7634
            r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]));
7635
          } else if (nargs == 6) {
7636
            w6w_t f = (w6w_t) func;
7637
            r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]),
7638
                  W(args[5]));
7639
          } else {
7640
            abort();
7641
          }
7642
        } else {
7643
          /* There are some floats */
7644
          switch (nargs) {
7645
            case 0:
7646
            case 1:
7647
            case 2:
7648
              if (IS_F(args[0]) && IS_F(args[1])) {
7649
                wff_t f = (wff_t) func;
7650
                r = f(F(args[0]), F(args[1]));
7651
              } else if (IS_F(args[0])) {
7652
                wfw_t f = (wfw_t) func;
7653
                r = f(F(args[0]), W(args[1]));
7654
              } else {
7655
                wwf_t f = (wwf_t) func;
7656
                r = f(W(args[0]), F(args[1]));
7657
              }
7658
              break;
7659
7660
            case 3:
7661
              if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) {
7662
                wwwf_t f = (wwwf_t) func;
7663
                r = f(W(args[0]), W(args[1]), F(args[2]));
7664
              } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) {
7665
                wwfw_t f = (wwfw_t) func;
7666
                r = f(W(args[0]), F(args[1]), W(args[2]));
7667
              } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) {
7668
                wwff_t f = (wwff_t) func;
7669
                r = f(W(args[0]), F(args[1]), F(args[2]));
7670
              } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) {
7671
                wfww_t f = (wfww_t) func;
7672
                r = f(F(args[0]), W(args[1]), W(args[2]));
7673
              } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) {
7674
                wfwf_t f = (wfwf_t) func;
7675
                r = f(F(args[0]), W(args[1]), F(args[2]));
7676
              } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) {
7677
                wffw_t f = (wffw_t) func;
7678
                r = f(F(args[0]), F(args[1]), W(args[2]));
7679
              } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) {
7680
                wfff_t f = (wfff_t) func;
7681
                r = f(F(args[0]), F(args[1]), F(args[2]));
7682
              } else {
7683
                // The above checks should be exhaustive
7684
                abort();
7685
              }
7686
              break;
7687
            default:
7688
              return -1;
7689
          }
7690
        }
7691
      } else {
7692
        /* There are some doubles */
7693
        switch (nargs) {
7694
          case 0:
7695
          case 1:
7696
          case 2:
7697
            if (IS_D(args[0]) && IS_D(args[1])) {
7698
              wdd_t f = (wdd_t) func;
7699
              r = f(D(args[0]), D(args[1]));
7700
            } else if (IS_D(args[0])) {
7701
              wdw_t f = (wdw_t) func;
7702
              r = f(D(args[0]), W(args[1]));
7703
            } else {
7704
              wwd_t f = (wwd_t) func;
7705
              r = f(W(args[0]), D(args[1]));
7706
            }
7707
            break;
7708
7709
          case 3:
7710
            if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) {
7711
              wwwd_t f = (wwwd_t) func;
7712
              r = f(W(args[0]), W(args[1]), D(args[2]));
7713
            } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) {
7714
              wwdw_t f = (wwdw_t) func;
7715
              r = f(W(args[0]), D(args[1]), W(args[2]));
7716
            } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) {
7717
              wwdd_t f = (wwdd_t) func;
7718
              r = f(W(args[0]), D(args[1]), D(args[2]));
7719
            } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) {
7720
              wdww_t f = (wdww_t) func;
7721
              r = f(D(args[0]), W(args[1]), W(args[2]));
7722
            } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) {
7723
              wdwd_t f = (wdwd_t) func;
7724
              r = f(D(args[0]), W(args[1]), D(args[2]));
7725
            } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) {
7726
              wddw_t f = (wddw_t) func;
7727
              r = f(D(args[0]), D(args[1]), W(args[2]));
7728
            } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) {
7729
              wddd_t f = (wddd_t) func;
7730
              r = f(D(args[0]), D(args[1]), D(args[2]));
7731
            } else {
7732
              // The above checks should be exhaustive
7733
              abort();
7734
            }
7735
            break;
7736
          default:
7737
            return -1;
7738
        }
7739
      }
7740
      res->v.i = (uint64_t) r;
7741
    } break;               /* }}} */
7742
    case FFI_CTYPE_BOOL: { /* {{{ */
7743
      ffi_word_t r;
7744
      if (doubles == 0) {
7745
        if (floats == 0) {
7746
          /*
7747
           * No double and no float args: we currently support up to 6
7748
           * word-sized arguments
7749
           */
7750
          if (nargs <= 4) {
7751
            b4w_t f = (b4w_t) func;
7752
            r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]));
7753
          } else if (nargs == 5) {
7754
            b5w_t f = (b5w_t) func;
7755
            r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]));
7756
          } else if (nargs == 6) {
7757
            b6w_t f = (b6w_t) func;
7758
            r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]),
7759
                  W(args[5]));
7760
          } else {
7761
            abort();
7762
          }
7763
        } else {
7764
          /* There are some floats */
7765
          switch (nargs) {
7766
            case 0:
7767
            case 1:
7768
            case 2:
7769
              if (IS_F(args[0]) && IS_F(args[1])) {
7770
                bff_t f = (bff_t) func;
7771
                r = f(F(args[0]), F(args[1]));
7772
              } else if (IS_F(args[0])) {
7773
                bfw_t f = (bfw_t) func;
7774
                r = f(F(args[0]), W(args[1]));
7775
              } else {
7776
                bwf_t f = (bwf_t) func;
7777
                r = f(W(args[0]), F(args[1]));
7778
              }
7779
              break;
7780
7781
            case 3:
7782
              if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) {
7783
                bwwf_t f = (bwwf_t) func;
7784
                r = f(W(args[0]), W(args[1]), F(args[2]));
7785
              } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) {
7786
                bwfw_t f = (bwfw_t) func;
7787
                r = f(W(args[0]), F(args[1]), W(args[2]));
7788
              } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) {
7789
                bwff_t f = (bwff_t) func;
7790
                r = f(W(args[0]), F(args[1]), F(args[2]));
7791
              } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) {
7792
                bfww_t f = (bfww_t) func;
7793
                r = f(F(args[0]), W(args[1]), W(args[2]));
7794
              } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) {
7795
                bfwf_t f = (bfwf_t) func;
7796
                r = f(F(args[0]), W(args[1]), F(args[2]));
7797
              } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) {
7798
                bffw_t f = (bffw_t) func;
7799
                r = f(F(args[0]), F(args[1]), W(args[2]));
7800
              } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) {
7801
                bfff_t f = (bfff_t) func;
7802
                r = f(F(args[0]), F(args[1]), F(args[2]));
7803
              } else {
7804
                // The above checks should be exhaustive
7805
                abort();
7806
              }
7807
              break;
7808
            default:
7809
              return -1;
7810
          }
7811
        }
7812
      } else {
7813
        /* There are some doubles */
7814
        switch (nargs) {
7815
          case 0:
7816
          case 1:
7817
          case 2:
7818
            if (IS_D(args[0]) && IS_D(args[1])) {
7819
              bdd_t f = (bdd_t) func;
7820
              r = f(D(args[0]), D(args[1]));
7821
            } else if (IS_D(args[0])) {
7822
              bdw_t f = (bdw_t) func;
7823
              r = f(D(args[0]), W(args[1]));
7824
            } else {
7825
              bwd_t f = (bwd_t) func;
7826
              r = f(W(args[0]), D(args[1]));
7827
            }
7828
            break;
7829
7830
          case 3:
7831
            if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) {
7832
              bwwd_t f = (bwwd_t) func;
7833
              r = f(W(args[0]), W(args[1]), D(args[2]));
7834
            } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) {
7835
              bwdw_t f = (bwdw_t) func;
7836
              r = f(W(args[0]), D(args[1]), W(args[2]));
7837
            } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) {
7838
              bwdd_t f = (bwdd_t) func;
7839
              r = f(W(args[0]), D(args[1]), D(args[2]));
7840
            } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) {
7841
              bdww_t f = (bdww_t) func;
7842
              r = f(D(args[0]), W(args[1]), W(args[2]));
7843
            } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) {
7844
              bdwd_t f = (bdwd_t) func;
7845
              r = f(D(args[0]), W(args[1]), D(args[2]));
7846
            } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) {
7847
              bddw_t f = (bddw_t) func;
7848
              r = f(D(args[0]), D(args[1]), W(args[2]));
7849
            } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) {
7850
              bddd_t f = (bddd_t) func;
7851
              r = f(D(args[0]), D(args[1]), D(args[2]));
7852
            } else {
7853
              // The above checks should be exhaustive
7854
              abort();
7855
            }
7856
            break;
7857
          default:
7858
            return -1;
7859
        }
7860
      }
7861
      res->v.i = (uint64_t) r;
7862
    } break;                 /* }}} */
7863
    case FFI_CTYPE_DOUBLE: { /* {{{ */
7864
      double r;
7865
      if (doubles == 0) {
7866
        /* No double args: we currently support up to 6 word-sized arguments
7867
         */
7868
        if (nargs <= 4) {
7869
          d4w_t f = (d4w_t) func;
7870
          r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]));
7871
        } else if (nargs == 5) {
7872
          d5w_t f = (d5w_t) func;
7873
          r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]));
7874
        } else if (nargs == 6) {
7875
          d6w_t f = (d6w_t) func;
7876
          r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]),
7877
                W(args[5]));
7878
        } else {
7879
          abort();
7880
        }
7881
      } else {
7882
        switch (nargs) {
7883
          case 0:
7884
          case 1:
7885
          case 2:
7886
            if (IS_D(args[0]) && IS_D(args[1])) {
7887
              ddd_t f = (ddd_t) func;
7888
              r = f(D(args[0]), D(args[1]));
7889
            } else if (IS_D(args[0])) {
7890
              ddw_t f = (ddw_t) func;
7891
              r = f(D(args[0]), W(args[1]));
7892
            } else {
7893
              dwd_t f = (dwd_t) func;
7894
              r = f(W(args[0]), D(args[1]));
7895
            }
7896
            break;
7897
7898
          case 3:
7899
            if (IS_W(args[0]) && IS_W(args[1]) && IS_D(args[2])) {
7900
              dwwd_t f = (dwwd_t) func;
7901
              r = f(W(args[0]), W(args[1]), D(args[2]));
7902
            } else if (IS_W(args[0]) && IS_D(args[1]) && IS_W(args[2])) {
7903
              dwdw_t f = (dwdw_t) func;
7904
              r = f(W(args[0]), D(args[1]), W(args[2]));
7905
            } else if (IS_W(args[0]) && IS_D(args[1]) && IS_D(args[2])) {
7906
              dwdd_t f = (dwdd_t) func;
7907
              r = f(W(args[0]), D(args[1]), D(args[2]));
7908
            } else if (IS_D(args[0]) && IS_W(args[1]) && IS_W(args[2])) {
7909
              ddww_t f = (ddww_t) func;
7910
              r = f(D(args[0]), W(args[1]), W(args[2]));
7911
            } else if (IS_D(args[0]) && IS_W(args[1]) && IS_D(args[2])) {
7912
              ddwd_t f = (ddwd_t) func;
7913
              r = f(D(args[0]), W(args[1]), D(args[2]));
7914
            } else if (IS_D(args[0]) && IS_D(args[1]) && IS_W(args[2])) {
7915
              dddw_t f = (dddw_t) func;
7916
              r = f(D(args[0]), D(args[1]), W(args[2]));
7917
            } else if (IS_D(args[0]) && IS_D(args[1]) && IS_D(args[2])) {
7918
              dddd_t f = (dddd_t) func;
7919
              r = f(D(args[0]), D(args[1]), D(args[2]));
7920
            } else {
7921
              // The above checks should be exhaustive
7922
              abort();
7923
            }
7924
            break;
7925
          default:
7926
            return -1;
7927
        }
7928
      }
7929
      res->v.d = r;
7930
    } break;                /* }}} */
7931
    case FFI_CTYPE_FLOAT: { /* {{{ */
7932
      double r;
7933
      if (floats == 0) {
7934
        /* No float args: we currently support up to 6 word-sized arguments
7935
         */
7936
        if (nargs <= 4) {
7937
          f4w_t f = (f4w_t) func;
7938
          r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]));
7939
        } else if (nargs == 5) {
7940
          f5w_t f = (f5w_t) func;
7941
          r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]));
7942
        } else if (nargs == 6) {
7943
          f6w_t f = (f6w_t) func;
7944
          r = f(W(args[0]), W(args[1]), W(args[2]), W(args[3]), W(args[4]),
7945
                W(args[5]));
7946
        } else {
7947
          abort();
7948
        }
7949
      } else {
7950
        /* There are some float args */
7951
        switch (nargs) {
7952
          case 0:
7953
          case 1:
7954
          case 2:
7955
            if (IS_F(args[0]) && IS_F(args[1])) {
7956
              fff_t f = (fff_t) func;
7957
              r = f(F(args[0]), F(args[1]));
7958
            } else if (IS_F(args[0])) {
7959
              ffw_t f = (ffw_t) func;
7960
              r = f(F(args[0]), W(args[1]));
7961
            } else {
7962
              fwf_t f = (fwf_t) func;
7963
              r = f(W(args[0]), F(args[1]));
7964
            }
7965
            break;
7966
7967
          case 3:
7968
            if (IS_W(args[0]) && IS_W(args[1]) && IS_F(args[2])) {
7969
              fwwf_t f = (fwwf_t) func;
7970
              r = f(W(args[0]), W(args[1]), F(args[2]));
7971
            } else if (IS_W(args[0]) && IS_F(args[1]) && IS_W(args[2])) {
7972
              fwfw_t f = (fwfw_t) func;
7973
              r = f(W(args[0]), F(args[1]), W(args[2]));
7974
            } else if (IS_W(args[0]) && IS_F(args[1]) && IS_F(args[2])) {
7975
              fwff_t f = (fwff_t) func;
7976
              r = f(W(args[0]), F(args[1]), F(args[2]));
7977
            } else if (IS_F(args[0]) && IS_W(args[1]) && IS_W(args[2])) {
7978
              ffww_t f = (ffww_t) func;
7979
              r = f(F(args[0]), W(args[1]), W(args[2]));
7980
            } else if (IS_F(args[0]) && IS_W(args[1]) && IS_F(args[2])) {
7981
              ffwf_t f = (ffwf_t) func;
7982
              r = f(F(args[0]), W(args[1]), F(args[2]));
7983
            } else if (IS_F(args[0]) && IS_F(args[1]) && IS_W(args[2])) {
7984
              fffw_t f = (fffw_t) func;
7985
              r = f(F(args[0]), F(args[1]), W(args[2]));
7986
            } else if (IS_F(args[0]) && IS_F(args[1]) && IS_F(args[2])) {
7987
              ffff_t f = (ffff_t) func;
7988
              r = f(F(args[0]), F(args[1]), F(args[2]));
7989
            } else {
7990
              // The above checks should be exhaustive
7991
              abort();
7992
            }
7993
            break;
7994
          default:
7995
            return -1;
7996
        }
7997
      }
7998
      res->v.f = r;
7999
    } break; /* }}} */
8000
  }
8001
8002
  return 0;
8003
}
8004
#ifdef MJS_MODULE_LINES
8005
#line 1 "mjs/src/mjs_array.c"
8006
#endif
8007
/*
8008
 * Copyright (c) 2017 Cesanta Software Limited
8009
 * All rights reserved
8010
 */
8011
8012
#include <stdio.h>
8013
/* Amalgamated: #include "common/str_util.h" */
8014
/* Amalgamated: #include "mjs/src/mjs_array.h" */
8015
/* Amalgamated: #include "mjs/src/mjs_conversion.h" */
8016
/* Amalgamated: #include "mjs/src/mjs_core.h" */
8017
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
8018
/* Amalgamated: #include "mjs/src/mjs_object.h" */
8019
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
8020
/* Amalgamated: #include "mjs/src/mjs_string.h" */
8021
/* Amalgamated: #include "mjs/src/mjs_util.h" */
8022
8023
#define SPLICE_NEW_ITEM_IDX 2
8024
8025
/* like c_snprintf but returns `size` if write is truncated */
8026
static int v_sprintf_s(char *buf, size_t size, const char *fmt, ...) {
8027
  size_t n;
8028
  va_list ap;
8029
  va_start(ap, fmt);
8030
  n = c_vsnprintf(buf, size, fmt, ap);
8031
  if (n > size) {
8032
    return size;
8033
  }
8034
  return n;
8035
}
8036
8037
mjs_val_t mjs_mk_array(struct mjs *mjs) {
8038
  mjs_val_t ret = mjs_mk_object(mjs);
8039
  /* change the tag to MJS_TAG_ARRAY */
8040
  ret &= ~MJS_TAG_MASK;
8041
  ret |= MJS_TAG_ARRAY;
8042
  return ret;
8043
}
8044
8045
56
int mjs_is_array(mjs_val_t v) {
8046
56
  return (v & MJS_TAG_MASK) == MJS_TAG_ARRAY;
8047
}
8048
8049
mjs_val_t mjs_array_get(struct mjs *mjs, mjs_val_t arr, unsigned long index) {
8050
  return mjs_array_get2(mjs, arr, index, NULL);
8051
}
8052
8053
mjs_val_t mjs_array_get2(struct mjs *mjs, mjs_val_t arr, unsigned long index,
8054
                         int *has) {
8055
  mjs_val_t res = MJS_UNDEFINED;
8056
8057
  if (has != NULL) {
8058
    *has = 0;
8059
  }
8060
8061
  if (mjs_is_object(arr)) {
8062
    struct mjs_property *p;
8063
    char buf[20];
8064
    int n = v_sprintf_s(buf, sizeof(buf), "%lu", index);
8065
    p = mjs_get_own_property(mjs, arr, buf, n);
8066
    if (p != NULL) {
8067
      if (has != NULL) {
8068
        *has = 1;
8069
      }
8070
      res = p->value;
8071
    }
8072
  }
8073
8074
  return res;
8075
}
8076
8077
unsigned long mjs_array_length(struct mjs *mjs, mjs_val_t v) {
8078
  struct mjs_property *p;
8079
  unsigned long len = 0;
8080
8081
  if (!mjs_is_object(v)) {
8082
    len = 0;
8083
    goto clean;
8084
  }
8085
8086
  for (p = get_object_struct(v)->properties; p != NULL; p = p->next) {
8087
    int ok = 0;
8088
    unsigned long n = 0;
8089
    str_to_ulong(mjs, p->name, &ok, &n);
8090
    if (ok && n >= len && n < 0xffffffff) {
8091
      len = n + 1;
8092
    }
8093
  }
8094
8095
clean:
8096
  return len;
8097
}
8098
8099
mjs_err_t mjs_array_set(struct mjs *mjs, mjs_val_t arr, unsigned long index,
8100
                        mjs_val_t v) {
8101
  mjs_err_t ret = MJS_OK;
8102
8103
  if (mjs_is_object(arr)) {
8104
    char buf[20];
8105
    int n = v_sprintf_s(buf, sizeof(buf), "%lu", index);
8106
    ret = mjs_set(mjs, arr, buf, n, v);
8107
  } else {
8108
    ret = MJS_TYPE_ERROR;
8109
  }
8110
8111
  return ret;
8112
}
8113
8114
void mjs_array_del(struct mjs *mjs, mjs_val_t arr, unsigned long index) {
8115
  char buf[20];
8116
  int n = v_sprintf_s(buf, sizeof(buf), "%lu", index);
8117
  mjs_del(mjs, arr, buf, n);
8118
}
8119
8120
mjs_err_t mjs_array_push(struct mjs *mjs, mjs_val_t arr, mjs_val_t v) {
8121
  return mjs_array_set(mjs, arr, mjs_array_length(mjs, arr), v);
8122
}
8123
8124
MJS_PRIVATE void mjs_array_push_internal(struct mjs *mjs) {
8125
  mjs_err_t rcode = MJS_OK;
8126
  mjs_val_t ret = MJS_UNDEFINED;
8127
  int nargs = mjs_nargs(mjs);
8128
  int i;
8129
8130
  /* Make sure that `this` is an array */
8131
  if (!mjs_check_arg(mjs, -1 /*this*/, "this", MJS_TYPE_OBJECT_ARRAY, NULL)) {
8132
    goto clean;
8133
  }
8134
8135
  /* Push all args */
8136
  for (i = 0; i < nargs; i++) {
8137
    rcode = mjs_array_push(mjs, mjs->vals.this_obj, mjs_arg(mjs, i));
8138
    if (rcode != MJS_OK) {
8139
      mjs_prepend_errorf(mjs, rcode, "");
8140
      goto clean;
8141
    }
8142
  }
8143
8144
  /* Return the new array length */
8145
  ret = mjs_mk_number(mjs, mjs_array_length(mjs, mjs->vals.this_obj));
8146
8147
clean:
8148
  mjs_return(mjs, ret);
8149
  return;
8150
}
8151
8152
static void move_item(struct mjs *mjs, mjs_val_t arr, unsigned long from,
8153
                      unsigned long to) {
8154
  mjs_val_t cur = mjs_array_get(mjs, arr, from);
8155
  mjs_array_set(mjs, arr, to, cur);
8156
  mjs_array_del(mjs, arr, from);
8157
}
8158
8159
MJS_PRIVATE void mjs_array_splice(struct mjs *mjs) {
8160
  int nargs = mjs_nargs(mjs);
8161
  mjs_err_t rcode = MJS_OK;
8162
  mjs_val_t ret = mjs_mk_array(mjs);
8163
  mjs_val_t start_v = MJS_UNDEFINED;
8164
  mjs_val_t deleteCount_v = MJS_UNDEFINED;
8165
  int start = 0;
8166
  int arr_len;
8167
  int delete_cnt = 0;
8168
  int new_items_cnt = 0;
8169
  int delta = 0;
8170
  int i;
8171
8172
  /* Make sure that `this` is an array */
8173
  if (!mjs_check_arg(mjs, -1 /*this*/, "this", MJS_TYPE_OBJECT_ARRAY, NULL)) {
8174
    goto clean;
8175
  }
8176
8177
  /* Get array length */
8178
  arr_len = mjs_array_length(mjs, mjs->vals.this_obj);
8179
8180
  /* get start from arg 0 */
8181
  if (!mjs_check_arg(mjs, 0, "start", MJS_TYPE_NUMBER, &start_v)) {
8182
    goto clean;
8183
  }
8184
  start = mjs_normalize_idx(mjs_get_int(mjs, start_v), arr_len);
8185
8186
  /* Handle deleteCount */
8187
  if (nargs >= SPLICE_NEW_ITEM_IDX) {
8188
    /* deleteCount is given; use it */
8189
    if (!mjs_check_arg(mjs, 1, "deleteCount", MJS_TYPE_NUMBER,
8190
                       &deleteCount_v)) {
8191
      goto clean;
8192
    }
8193
    delete_cnt = mjs_get_int(mjs, deleteCount_v);
8194
    new_items_cnt = nargs - SPLICE_NEW_ITEM_IDX;
8195
  } else {
8196
    /* deleteCount is not given; assume the end of the array */
8197
    delete_cnt = arr_len - start;
8198
  }
8199
  if (delete_cnt > arr_len - start) {
8200
    delete_cnt = arr_len - start;
8201
  } else if (delete_cnt < 0) {
8202
    delete_cnt = 0;
8203
  }
8204
8205
  /* delta at which subsequent array items should be moved */
8206
  delta = new_items_cnt - delete_cnt;
8207
8208
  /*
8209
   * copy items which are going to be deleted to the separate array (will be
8210
   * returned)
8211
   */
8212
  for (i = 0; i < delete_cnt; i++) {
8213
    mjs_val_t cur = mjs_array_get(mjs, mjs->vals.this_obj, start + i);
8214
    rcode = mjs_array_push(mjs, ret, cur);
8215
    if (rcode != MJS_OK) {
8216
      mjs_prepend_errorf(mjs, rcode, "");
8217
      goto clean;
8218
    }
8219
  }
8220
8221
  /* If needed, move subsequent items */
8222
  if (delta < 0) {
8223
    for (i = start; i < arr_len; i++) {
8224
      if (i >= start - delta) {
8225
        move_item(mjs, mjs->vals.this_obj, i, i + delta);
8226
      } else {
8227
        mjs_array_del(mjs, mjs->vals.this_obj, i);
8228
      }
8229
    }
8230
  } else if (delta > 0) {
8231
    for (i = arr_len - 1; i >= start; i--) {
8232
      move_item(mjs, mjs->vals.this_obj, i, i + delta);
8233
    }
8234
  }
8235
8236
  /* Set new items to the array */
8237
  for (i = 0; i < nargs - SPLICE_NEW_ITEM_IDX; i++) {
8238
    mjs_array_set(mjs, mjs->vals.this_obj, start + i,
8239
                  mjs_arg(mjs, SPLICE_NEW_ITEM_IDX + i));
8240
  }
8241
8242
clean:
8243
  mjs_return(mjs, ret);
8244
}
8245
#ifdef MJS_MODULE_LINES
8246
#line 1 "mjs/src/mjs_bcode.c"
8247
#endif
8248
/*
8249
 * Copyright (c) 2017 Cesanta Software Limited
8250
 * All rights reserved
8251
 */
8252
8253
/* Amalgamated: #include "common/cs_varint.h" */
8254
8255
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
8256
/* Amalgamated: #include "mjs/src/mjs_bcode.h" */
8257
/* Amalgamated: #include "mjs/src/mjs_core.h" */
8258
/* Amalgamated: #include "mjs/src/mjs_tok.h" */
8259
8260
780
static void add_lineno_map_item(struct pstate *pstate) {
8261
780
  if (pstate->last_emitted_line_no < pstate->line_no) {
8262
9
    int offset = pstate->cur_idx - pstate->start_bcode_idx;
8263
9
    size_t offset_llen = cs_varint_llen(offset);
8264
9
    size_t lineno_llen = cs_varint_llen(pstate->line_no);
8265
9
    mbuf_resize(&pstate->offset_lineno_map,
8266
9
                pstate->offset_lineno_map.size + offset_llen + lineno_llen);
8267
8268
    /* put offset */
8269
9
    cs_varint_encode(offset, (uint8_t *) pstate->offset_lineno_map.buf +
8270
                                 pstate->offset_lineno_map.len,
8271
                     offset_llen);
8272
9
    pstate->offset_lineno_map.len += offset_llen;
8273
8274
    /* put line_no */
8275
9
    cs_varint_encode(pstate->line_no,
8276
9
                     (uint8_t *) pstate->offset_lineno_map.buf +
8277
                         pstate->offset_lineno_map.len,
8278
                     lineno_llen);
8279
9
    pstate->offset_lineno_map.len += lineno_llen;
8280
8281
9
    pstate->last_emitted_line_no = pstate->line_no;
8282
  }
8283
780
}
8284
8285
663
MJS_PRIVATE void emit_byte(struct pstate *pstate, uint8_t byte) {
8286
663
  add_lineno_map_item(pstate);
8287
663
  mbuf_insert(&pstate->mjs->bcode_gen, pstate->cur_idx, &byte, sizeof(byte));
8288
663
  pstate->cur_idx += sizeof(byte);
8289
663
}
8290
8291
42
MJS_PRIVATE void emit_int(struct pstate *pstate, int64_t n) {
8292
42
  struct mbuf *b = &pstate->mjs->bcode_gen;
8293
42
  size_t llen = cs_varint_llen(n);
8294
42
  add_lineno_map_item(pstate);
8295
42
  mbuf_insert(b, pstate->cur_idx, NULL, llen);
8296
42
  cs_varint_encode(n, (uint8_t *) b->buf + pstate->cur_idx, llen);
8297
42
  pstate->cur_idx += llen;
8298
42
}
8299
8300
75
MJS_PRIVATE void emit_str(struct pstate *pstate, const char *ptr, size_t len) {
8301
75
  struct mbuf *b = &pstate->mjs->bcode_gen;
8302
75
  size_t llen = cs_varint_llen(len);
8303
75
  add_lineno_map_item(pstate);
8304
75
  mbuf_insert(b, pstate->cur_idx, NULL, llen + len);
8305
75
  cs_varint_encode(len, (uint8_t *) b->buf + pstate->cur_idx, llen);
8306
75
  memcpy(b->buf + pstate->cur_idx + llen, ptr, len);
8307
75
  pstate->cur_idx += llen + len;
8308
75
}
8309
8310
10
MJS_PRIVATE int mjs_bcode_insert_offset(struct pstate *p, struct mjs *mjs,
8311
                                        size_t offset, size_t v) {
8312
10
  int llen = (int) cs_varint_llen(v);
8313
10
  int diff = llen - MJS_INIT_OFFSET_SIZE;
8314
10
  assert(offset < mjs->bcode_gen.len);
8315
10
  if (diff > 0) {
8316
    mbuf_resize(&mjs->bcode_gen, mjs->bcode_gen.size + diff);
8317
  }
8318
  /*
8319
   * Offset is going to take more than one was reserved, so, move the data
8320
   * forward
8321
   */
8322
20
  memmove(mjs->bcode_gen.buf + offset + llen,
8323
10
          mjs->bcode_gen.buf + offset + MJS_INIT_OFFSET_SIZE,
8324
10
          mjs->bcode_gen.len - offset - MJS_INIT_OFFSET_SIZE);
8325
10
  mjs->bcode_gen.len += diff;
8326
10
  cs_varint_encode(v, (uint8_t *) mjs->bcode_gen.buf + offset, llen);
8327
8328
  /*
8329
   * If current parsing index is after the offset at which we've inserted new
8330
   * varint, the index might need to be adjusted
8331
   */
8332
10
  if (p->cur_idx >= (int) offset) {
8333
10
    p->cur_idx += diff;
8334
  }
8335
10
  return diff;
8336
}
8337
8338
66
MJS_PRIVATE void mjs_bcode_part_add(struct mjs *mjs,
8339
                                    const struct mjs_bcode_part *bp) {
8340
66
  mbuf_append(&mjs->bcode_parts, bp, sizeof(*bp));
8341
66
}
8342
8343
298
MJS_PRIVATE struct mjs_bcode_part *mjs_bcode_part_get(struct mjs *mjs,
8344
                                                      int num) {
8345
298
  assert(num < mjs_bcode_parts_cnt(mjs));
8346
298
  return (struct mjs_bcode_part *) (mjs->bcode_parts.buf +
8347
                                    num * sizeof(struct mjs_bcode_part));
8348
}
8349
8350
232
MJS_PRIVATE struct mjs_bcode_part *mjs_bcode_part_get_by_offset(struct mjs *mjs,
8351
                                                                size_t offset) {
8352
  int i;
8353
232
  int parts_cnt = mjs_bcode_parts_cnt(mjs);
8354
232
  struct mjs_bcode_part *bp = NULL;
8355
8356
232
  if (offset >= mjs->bcode_len) {
8357
    return NULL;
8358
  }
8359
8360
232
  for (i = 0; i < parts_cnt; i++) {
8361
232
    bp = mjs_bcode_part_get(mjs, i);
8362
232
    if (offset < bp->start_idx + bp->data.len) {
8363
232
      break;
8364
    }
8365
  }
8366
8367
  /* given the non-corrupted data, the needed part must be found */
8368
232
  assert(i < parts_cnt);
8369
8370
232
  return bp;
8371
}
8372
8373
608
MJS_PRIVATE int mjs_bcode_parts_cnt(struct mjs *mjs) {
8374
608
  return mjs->bcode_parts.len / sizeof(struct mjs_bcode_part);
8375
}
8376
8377
66
MJS_PRIVATE void mjs_bcode_commit(struct mjs *mjs) {
8378
  struct mjs_bcode_part bp;
8379
66
  memset(&bp, 0, sizeof(bp));
8380
8381
  /* Make sure the bcode doesn't occupy any extra space */
8382
66
  mbuf_trim(&mjs->bcode_gen);
8383
8384
  /* Transfer the ownership of the bcode data */
8385
66
  bp.data.p = mjs->bcode_gen.buf;
8386
66
  bp.data.len = mjs->bcode_gen.len;
8387
66
  mbuf_init(&mjs->bcode_gen, 0);
8388
8389
66
  bp.start_idx = mjs->bcode_len;
8390
66
  bp.exec_res = MJS_ERRS_CNT;
8391
8392
66
  mjs_bcode_part_add(mjs, &bp);
8393
8394
66
  mjs->bcode_len += bp.data.len;
8395
66
}
8396
#ifdef MJS_MODULE_LINES
8397
#line 1 "mjs/src/mjs_builtin.c"
8398
#endif
8399
/*
8400
 * Copyright (c) 2017 Cesanta Software Limited
8401
 * All rights reserved
8402
 */
8403
8404
/* Amalgamated: #include "mjs/src/mjs_bcode.h" */
8405
/* Amalgamated: #include "mjs/src/mjs_core.h" */
8406
/* Amalgamated: #include "mjs/src/mjs_dataview.h" */
8407
/* Amalgamated: #include "mjs/src/mjs_exec.h" */
8408
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
8409
/* Amalgamated: #include "mjs/src/mjs_json.h" */
8410
/* Amalgamated: #include "mjs/src/mjs_object.h" */
8411
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
8412
/* Amalgamated: #include "mjs/src/mjs_string.h" */
8413
/* Amalgamated: #include "mjs/src/mjs_util.h" */
8414
8415
static void mjs_print(struct mjs *mjs) {
8416
  size_t i, num_args = mjs_nargs(mjs);
8417
  for (i = 0; i < num_args; i++) {
8418
    mjs_fprintf(mjs_arg(mjs, i), mjs, stdout);
8419
    putchar(' ');
8420
  }
8421
  putchar('\n');
8422
  mjs_return(mjs, MJS_UNDEFINED);
8423
}
8424
8425
/*
8426
 * If the file with the given filename was already loaded, returns the
8427
 * corresponding bcode part; otherwise returns NULL.
8428
 */
8429
static struct mjs_bcode_part *mjs_get_loaded_file_bcode(struct mjs *mjs,
8430
                                                        const char *filename) {
8431
  int parts_cnt = mjs_bcode_parts_cnt(mjs);
8432
  int i;
8433
8434
  if (filename == NULL) {
8435
    return 0;
8436
  }
8437
8438
  for (i = 0; i < parts_cnt; i++) {
8439
    struct mjs_bcode_part *bp = mjs_bcode_part_get(mjs, i);
8440
    const char *cur_fn = mjs_get_bcode_filename(mjs, bp);
8441
    if (strcmp(filename, cur_fn) == 0) {
8442
      return bp;
8443
    }
8444
  }
8445
  return NULL;
8446
}
8447
8448
static void mjs_load(struct mjs *mjs) {
8449
  mjs_val_t res = MJS_UNDEFINED;
8450
  mjs_val_t arg0 = mjs_arg(mjs, 0);
8451
  mjs_val_t arg1 = mjs_arg(mjs, 1);
8452
  int custom_global = 0; /* whether the custom global object was provided */
8453
8454
  if (mjs_is_string(arg0)) {
8455
    const char *path = mjs_get_cstring(mjs, &arg0);
8456
    struct mjs_bcode_part *bp = NULL;
8457
    mjs_err_t ret;
8458
8459
    if (mjs_is_object(arg1)) {
8460
      custom_global = 1;
8461
      push_mjs_val(&mjs->scopes, arg1);
8462
    }
8463
    bp = mjs_get_loaded_file_bcode(mjs, path);
8464
    if (bp == NULL) {
8465
      /* File was not loaded before, so, load */
8466
      ret = mjs_exec_file(mjs, path, &res);
8467
    } else {
8468
      /*
8469
       * File was already loaded before, so if it was evaluated successfully,
8470
       * then skip the evaluation at all (and assume MJS_OK); otherwise
8471
       * re-evaluate it again.
8472
       *
8473
       * However, if the custom global object was provided, then reevaluate
8474
       * the file in any case.
8475
       */
8476
      if (bp->exec_res != MJS_OK || custom_global) {
8477
        ret = mjs_execute(mjs, bp->start_idx, &res);
8478
      } else {
8479
        ret = MJS_OK;
8480
      }
8481
    }
8482
    if (ret != MJS_OK) {
8483
      /*
8484
       * arg0 and path might be invalidated by executing a file, so refresh
8485
       * them
8486
       */
8487
      arg0 = mjs_arg(mjs, 0);
8488
      path = mjs_get_cstring(mjs, &arg0);
8489
      mjs_prepend_errorf(mjs, ret, "failed to exec file \"%s\"", path);
8490
      goto clean;
8491
    }
8492
8493
  clean:
8494
    if (custom_global) {
8495
      mjs_pop_val(&mjs->scopes);
8496
    }
8497
  }
8498
  mjs_return(mjs, res);
8499
}
8500
8501
static void mjs_get_mjs(struct mjs *mjs) {
8502
  mjs_return(mjs, mjs_mk_foreign(mjs, mjs));
8503
}
8504
8505
static void mjs_chr(struct mjs *mjs) {
8506
  mjs_val_t arg0 = mjs_arg(mjs, 0), res = MJS_NULL;
8507
  int n = mjs_get_int(mjs, arg0);
8508
  if (mjs_is_number(arg0) && n >= 0 && n <= 255) {
8509
    uint8_t s = n;
8510
    res = mjs_mk_string(mjs, (const char *) &s, sizeof(s), 1);
8511
  }
8512
  mjs_return(mjs, res);
8513
}
8514
8515
static void mjs_do_gc(struct mjs *mjs) {
8516
  mjs_val_t arg0 = mjs_arg(mjs, 0);
8517
  mjs_gc(mjs, mjs_is_boolean(arg0) ? mjs_get_bool(mjs, arg0) : 0);
8518
  mjs_return(mjs, arg0);
8519
}
8520
8521
static void mjs_s2o(struct mjs *mjs) {
8522
  mjs_return(mjs,
8523
             mjs_struct_to_obj(mjs, mjs_get_ptr(mjs, mjs_arg(mjs, 0)),
8524
                               (const struct mjs_c_struct_member *) mjs_get_ptr(
8525
                                   mjs, mjs_arg(mjs, 1))));
8526
}
8527
8528
78
void mjs_init_builtin(struct mjs *mjs, mjs_val_t obj) {
8529
  mjs_val_t v;
8530
8531
78
  mjs_set(mjs, obj, "global", ~0, obj);
8532
8533
78
  mjs_set(mjs, obj, "load", ~0,
8534
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_load));
8535
78
  mjs_set(mjs, obj, "print", ~0,
8536
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_print));
8537
78
  mjs_set(mjs, obj, "ffi", ~0,
8538
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_ffi_call));
8539
78
  mjs_set(mjs, obj, "ffi_cb_free", ~0,
8540
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_ffi_cb_free));
8541
78
  mjs_set(mjs, obj, "mkstr", ~0,
8542
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_mkstr));
8543
78
  mjs_set(mjs, obj, "getMJS", ~0,
8544
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_get_mjs));
8545
78
  mjs_set(mjs, obj, "die", ~0,
8546
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_die));
8547
78
  mjs_set(mjs, obj, "gc", ~0,
8548
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_do_gc));
8549
78
  mjs_set(mjs, obj, "chr", ~0,
8550
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_chr));
8551
78
  mjs_set(mjs, obj, "s2o", ~0,
8552
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_s2o));
8553
8554
  /*
8555
   * Populate JSON.parse() and JSON.stringify()
8556
   */
8557
78
  v = mjs_mk_object(mjs);
8558
78
  mjs_set(mjs, v, "stringify", ~0,
8559
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_op_json_stringify));
8560
78
  mjs_set(mjs, v, "parse", ~0,
8561
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_op_json_parse));
8562
78
  mjs_set(mjs, obj, "JSON", ~0, v);
8563
8564
  /*
8565
   * Populate Object.create()
8566
   */
8567
78
  v = mjs_mk_object(mjs);
8568
78
  mjs_set(mjs, v, "create", ~0,
8569
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_op_create_object));
8570
78
  mjs_set(mjs, obj, "Object", ~0, v);
8571
8572
  /*
8573
   * Populate numeric stuff
8574
   */
8575
78
  mjs_set(mjs, obj, "NaN", ~0, MJS_TAG_NAN);
8576
78
  mjs_set(mjs, obj, "isNaN", ~0,
8577
          mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_op_isnan));
8578
78
}
8579
#ifdef MJS_MODULE_LINES
8580
#line 1 "mjs/src/mjs_conversion.c"
8581
#endif
8582
/*
8583
 * Copyright (c) 2016 Cesanta Software Limited
8584
 * All rights reserved
8585
 */
8586
8587
/* Amalgamated: #include "mjs/src/mjs_conversion.h" */
8588
/* Amalgamated: #include "mjs/src/mjs_object.h" */
8589
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
8590
/* Amalgamated: #include "mjs/src/mjs_string.h" */
8591
/* Amalgamated: #include "mjs/src/mjs_util.h" */
8592
8593
42
MJS_PRIVATE mjs_err_t mjs_to_string(struct mjs *mjs, mjs_val_t *v, char **p,
8594
                                    size_t *sizep, int *need_free) {
8595
42
  mjs_err_t ret = MJS_OK;
8596
8597
42
  *p = NULL;
8598
42
  *sizep = 0;
8599
42
  *need_free = 0;
8600
8601
42
  if (mjs_is_string(*v)) {
8602
42
    *p = (char *) mjs_get_string(mjs, v, sizep);
8603
  } else if (mjs_is_number(*v)) {
8604
    char buf[50] = "";
8605
    struct json_out out = JSON_OUT_BUF(buf, sizeof(buf));
8606
    mjs_jprintf(*v, mjs, &out);
8607
    *sizep = strlen(buf);
8608
    *p = malloc(*sizep + 1);
8609
    if (*p == NULL) {
8610
      ret = MJS_OUT_OF_MEMORY;
8611
      goto clean;
8612
    }
8613
    memmove(*p, buf, *sizep+1);
8614
    *need_free = 1;
8615
  } else if (mjs_is_boolean(*v)) {
8616
    if (mjs_get_bool(mjs, *v)) {
8617
      *p = "true";
8618
      *sizep = 4;
8619
    } else {
8620
      *p = "false";
8621
      *sizep = 5;
8622
    }
8623
  } else if (mjs_is_undefined(*v)) {
8624
    *p = "undefined";
8625
    *sizep = 9;
8626
  } else if (mjs_is_null(*v)) {
8627
    *p = "null";
8628
    *sizep = 4;
8629
  } else if (mjs_is_object(*v)) {
8630
    ret = MJS_TYPE_ERROR;
8631
    mjs_set_errorf(mjs, ret,
8632
                   "conversion from object to string is not supported");
8633
  } else if (mjs_is_foreign(*v)) {
8634
    *p = "TODO_foreign";
8635
    *sizep = 12;
8636
  } else {
8637
    ret = MJS_TYPE_ERROR;
8638
    mjs_set_errorf(mjs, ret, "unknown type to convert to string");
8639
  }
8640
8641
clean:
8642
42
  return ret;
8643
}
8644
8645
MJS_PRIVATE mjs_val_t mjs_to_boolean_v(struct mjs *mjs, mjs_val_t v) {
8646
  size_t len;
8647
  int is_truthy;
8648
8649
  is_truthy =
8650
      ((mjs_is_boolean(v) && mjs_get_bool(mjs, v)) ||
8651
       (mjs_is_number(v) && mjs_get_double(mjs, v) != 0.0) ||
8652
       (mjs_is_string(v) && mjs_get_string(mjs, &v, &len) && len > 0) ||
8653
       (mjs_is_function(v)) || (mjs_is_foreign(v)) || (mjs_is_object(v))) &&
8654
      v != MJS_TAG_NAN;
8655
8656
  return mjs_mk_boolean(mjs, is_truthy);
8657
}
8658
8659
MJS_PRIVATE int mjs_is_truthy(struct mjs *mjs, mjs_val_t v) {
8660
  return mjs_get_bool(mjs, mjs_to_boolean_v(mjs, v));
8661
}
8662
#ifdef MJS_MODULE_LINES
8663
#line 1 "mjs/src/mjs_core.c"
8664
#endif
8665
/*
8666
 * Copyright (c) 2017 Cesanta Software Limited
8667
 * All rights reserved
8668
 */
8669
8670
/* Amalgamated: #include "common/cs_varint.h" */
8671
/* Amalgamated: #include "common/str_util.h" */
8672
8673
/* Amalgamated: #include "mjs/src/mjs_bcode.h" */
8674
/* Amalgamated: #include "mjs/src/mjs_builtin.h" */
8675
/* Amalgamated: #include "mjs/src/mjs_core.h" */
8676
/* Amalgamated: #include "mjs/src/mjs_exec.h" */
8677
/* Amalgamated: #include "mjs/src/mjs_ffi.h" */
8678
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
8679
/* Amalgamated: #include "mjs/src/mjs_license.h" */
8680
/* Amalgamated: #include "mjs/src/mjs_object.h" */
8681
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
8682
/* Amalgamated: #include "mjs/src/mjs_string.h" */
8683
/* Amalgamated: #include "mjs/src/mjs_util.h" */
8684
8685
#ifndef MJS_OBJECT_ARENA_SIZE
8686
#define MJS_OBJECT_ARENA_SIZE 20
8687
#endif
8688
#ifndef MJS_PROPERTY_ARENA_SIZE
8689
#define MJS_PROPERTY_ARENA_SIZE 20
8690
#endif
8691
#ifndef MJS_FUNC_FFI_ARENA_SIZE
8692
#define MJS_FUNC_FFI_ARENA_SIZE 20
8693
#endif
8694
8695
#ifndef MJS_OBJECT_ARENA_INC_SIZE
8696
#define MJS_OBJECT_ARENA_INC_SIZE 10
8697
#endif
8698
#ifndef MJS_PROPERTY_ARENA_INC_SIZE
8699
#define MJS_PROPERTY_ARENA_INC_SIZE 10
8700
#endif
8701
#ifndef MJS_FUNC_FFI_ARENA_INC_SIZE
8702
#define MJS_FUNC_FFI_ARENA_INC_SIZE 10
8703
#endif
8704
8705
78
void mjs_destroy(struct mjs *mjs) {
8706
  {
8707
78
    int parts_cnt = mjs_bcode_parts_cnt(mjs);
8708
    int i;
8709
144
    for (i = 0; i < parts_cnt; i++) {
8710
66
      struct mjs_bcode_part *bp = mjs_bcode_part_get(mjs, i);
8711
66
      if (!bp->in_rom) {
8712
66
        free((void *) bp->data.p);
8713
      }
8714
    }
8715
  }
8716
8717
78
  mbuf_free(&mjs->bcode_gen);
8718
78
  mbuf_free(&mjs->bcode_parts);
8719
78
  mbuf_free(&mjs->stack);
8720
78
  mbuf_free(&mjs->call_stack);
8721
78
  mbuf_free(&mjs->arg_stack);
8722
78
  mbuf_free(&mjs->owned_strings);
8723
78
  mbuf_free(&mjs->foreign_strings);
8724
78
  mbuf_free(&mjs->owned_values);
8725
78
  mbuf_free(&mjs->scopes);
8726
78
  mbuf_free(&mjs->loop_addresses);
8727
78
  mbuf_free(&mjs->json_visited_stack);
8728
78
  free(mjs->error_msg);
8729
78
  free(mjs->stack_trace);
8730
78
  mjs_ffi_args_free_list(mjs);
8731
78
  gc_arena_destroy(mjs, &mjs->object_arena);
8732
78
  gc_arena_destroy(mjs, &mjs->property_arena);
8733
78
  gc_arena_destroy(mjs, &mjs->ffi_sig_arena);
8734
78
  free(mjs);
8735
78
}
8736
8737
78
struct mjs *mjs_create(void) {
8738
  mjs_val_t global_object;
8739
78
  struct mjs *mjs = calloc(1, sizeof(*mjs));
8740
78
  mbuf_init(&mjs->stack, 0);
8741
78
  mbuf_init(&mjs->call_stack, 0);
8742
78
  mbuf_init(&mjs->arg_stack, 0);
8743
78
  mbuf_init(&mjs->owned_strings, 0);
8744
78
  mbuf_init(&mjs->foreign_strings, 0);
8745
78
  mbuf_init(&mjs->bcode_gen, 0);
8746
78
  mbuf_init(&mjs->bcode_parts, 0);
8747
78
  mbuf_init(&mjs->owned_values, 0);
8748
78
  mbuf_init(&mjs->scopes, 0);
8749
78
  mbuf_init(&mjs->loop_addresses, 0);
8750
78
  mbuf_init(&mjs->json_visited_stack, 0);
8751
8752
78
  mjs->bcode_len = 0;
8753
8754
  /*
8755
   * The compacting GC exploits the null terminator of the previous string as a
8756
   * marker.
8757
   */
8758
  {
8759
78
    char z = 0;
8760
78
    mbuf_append(&mjs->owned_strings, &z, 1);
8761
  }
8762
8763
78
  gc_arena_init(&mjs->object_arena, sizeof(struct mjs_object),
8764
                MJS_OBJECT_ARENA_SIZE, MJS_OBJECT_ARENA_INC_SIZE);
8765
78
  gc_arena_init(&mjs->property_arena, sizeof(struct mjs_property),
8766
                MJS_PROPERTY_ARENA_SIZE, MJS_PROPERTY_ARENA_INC_SIZE);
8767
78
  gc_arena_init(&mjs->ffi_sig_arena, sizeof(struct mjs_ffi_sig),
8768
                MJS_FUNC_FFI_ARENA_SIZE, MJS_FUNC_FFI_ARENA_INC_SIZE);
8769
78
  mjs->ffi_sig_arena.destructor = mjs_ffi_sig_destructor;
8770
8771
78
  global_object = mjs_mk_object(mjs);
8772
78
  mjs_init_builtin(mjs, global_object);
8773
78
  mjs_set_ffi_resolver(mjs, dlsym);
8774
78
  push_mjs_val(&mjs->scopes, global_object);
8775
78
  mjs->vals.this_obj = MJS_UNDEFINED;
8776
78
  mjs->vals.dataview_proto = MJS_UNDEFINED;
8777
8778
78
  return mjs;
8779
}
8780
8781
124
mjs_err_t mjs_set_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt, ...) {
8782
  va_list ap;
8783
124
  va_start(ap, fmt);
8784
124
  free(mjs->error_msg);
8785
124
  mjs->error_msg = NULL;
8786
124
  mjs->error = err;
8787
124
  if (fmt != NULL) {
8788
58
    mg_avprintf(&mjs->error_msg, 0, fmt, ap);
8789
  }
8790
124
  va_end(ap);
8791
124
  return err;
8792
}
8793
8794
4
mjs_err_t mjs_prepend_errorf(struct mjs *mjs, mjs_err_t err, const char *fmt,
8795
                             ...) {
8796
4
  char *old_error_msg = mjs->error_msg;
8797
4
  char *new_error_msg = NULL;
8798
  va_list ap;
8799
4
  va_start(ap, fmt);
8800
8801
  /* err should never be MJS_OK here */
8802
4
  assert(err != MJS_OK);
8803
8804
4
  mjs->error_msg = NULL;
8805
  /* set error if only it wasn't already set to some error */
8806
4
  if (mjs->error == MJS_OK) {
8807
4
    mjs->error = err;
8808
  }
8809
4
  mg_avprintf(&new_error_msg, 0, fmt, ap);
8810
4
  va_end(ap);
8811
8812
4
  if (old_error_msg != NULL) {
8813
    mg_asprintf(&mjs->error_msg, 0, "%s: %s", new_error_msg, old_error_msg);
8814
    free(new_error_msg);
8815
    free(old_error_msg);
8816
  } else {
8817
4
    mjs->error_msg = new_error_msg;
8818
  }
8819
4
  return err;
8820
}
8821
8822
12
void mjs_print_error(struct mjs *mjs, FILE *fp, const char *msg,
8823
                     int print_stack_trace) {
8824

12
  if (print_stack_trace && mjs->stack_trace != NULL) {
8825
    fprintf(fp, "%s", mjs->stack_trace);
8826
  }
8827
8828
12
  if (msg == NULL) {
8829
12
    msg = "MJS error";
8830
  }
8831
8832
12
  fprintf(fp, "%s: %s\n", msg, mjs_strerror(mjs, mjs->error));
8833
12
}
8834
8835
MJS_PRIVATE void mjs_die(struct mjs *mjs) {
8836
  mjs_val_t msg_v = MJS_UNDEFINED;
8837
  const char *msg = NULL;
8838
  size_t msg_len = 0;
8839
8840
  /* get idx from arg 0 */
8841
  if (!mjs_check_arg(mjs, 0, "msg", MJS_TYPE_STRING, &msg_v)) {
8842
    goto clean;
8843
  }
8844
8845
  msg = mjs_get_string(mjs, &msg_v, &msg_len);
8846
8847
  /* TODO(dfrank): take error type as an argument */
8848
  mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "%.*s", (int) msg_len, msg);
8849
8850
clean:
8851
  mjs_return(mjs, MJS_UNDEFINED);
8852
}
8853
8854
12
const char *mjs_strerror(struct mjs *mjs, enum mjs_err err) {
8855
12
  const char *err_names[] = {
8856
      "NO_ERROR",        "SYNTAX_ERROR",    "REFERENCE_ERROR",
8857
      "TYPE_ERROR",      "OUT_OF_MEMORY",   "INTERNAL_ERROR",
8858
      "NOT_IMPLEMENTED", "FILE_OPEN_ERROR", "BAD_ARGUMENTS"};
8859
36
  return mjs->error_msg == NULL || mjs->error_msg[0] == '\0' ? err_names[err]
8860
12
                                                             : mjs->error_msg;
8861
}
8862
8863
MJS_PRIVATE size_t mjs_get_func_addr(mjs_val_t v) {
8864
  return v & ~MJS_TAG_MASK;
8865
}
8866
8867
1
MJS_PRIVATE enum mjs_type mjs_get_type(mjs_val_t v) {
8868
  int tag;
8869
1
  if (mjs_is_number(v)) {
8870
    return MJS_TYPE_NUMBER;
8871
  }
8872
1
  tag = (v & MJS_TAG_MASK) >> 48;
8873


1
  switch (tag) {
8874
    case MJS_TAG_FOREIGN >> 48:
8875
      return MJS_TYPE_FOREIGN;
8876
    case MJS_TAG_UNDEFINED >> 48:
8877
      return MJS_TYPE_UNDEFINED;
8878
    case MJS_TAG_OBJECT >> 48:
8879
      return MJS_TYPE_OBJECT_GENERIC;
8880
    case MJS_TAG_ARRAY >> 48:
8881
      return MJS_TYPE_OBJECT_ARRAY;
8882
    case MJS_TAG_FUNCTION >> 48:
8883
      return MJS_TYPE_OBJECT_FUNCTION;
8884
    case MJS_TAG_STRING_I >> 48:
8885
    case MJS_TAG_STRING_O >> 48:
8886
    case MJS_TAG_STRING_F >> 48:
8887
    case MJS_TAG_STRING_D >> 48:
8888
    case MJS_TAG_STRING_5 >> 48:
8889
1
      return MJS_TYPE_STRING;
8890
    case MJS_TAG_BOOLEAN >> 48:
8891
      return MJS_TYPE_BOOLEAN;
8892
    case MJS_TAG_NULL >> 48:
8893
      return MJS_TYPE_NULL;
8894
    default:
8895
      abort();
8896
      return MJS_TYPE_UNDEFINED;
8897
  }
8898
}
8899
8900
mjs_val_t mjs_get_global(struct mjs *mjs) {
8901
  return *vptr(&mjs->scopes, 0);
8902
}
8903
8904
50
static void mjs_append_stack_trace_line(struct mjs *mjs, size_t offset) {
8905
50
  if (offset != MJS_BCODE_OFFSET_EXIT) {
8906
50
    const char *filename = mjs_get_bcode_filename_by_offset(mjs, offset);
8907
50
    int line_no = mjs_get_lineno_by_offset(mjs, offset);
8908
50
    char *new_line = NULL;
8909
50
    const char *fmt = "  at %s:%d\n";
8910
50
    if (filename == NULL) {
8911
      fprintf(stderr,
8912
              "ERROR during stack trace generation: wrong bcode offset %d\n",
8913
              (int) offset);
8914
      filename = "<unknown-filename>";
8915
    }
8916
50
    mg_asprintf(&new_line, 0, fmt, filename, line_no);
8917
8918
50
    if (mjs->stack_trace != NULL) {
8919
      char *old = mjs->stack_trace;
8920
      mg_asprintf(&mjs->stack_trace, 0, "%s%s", mjs->stack_trace, new_line);
8921
      free(old);
8922
      free(new_line);
8923
    } else {
8924
50
      mjs->stack_trace = new_line;
8925
    }
8926
  }
8927
50
}
8928
8929
50
MJS_PRIVATE void mjs_gen_stack_trace(struct mjs *mjs, size_t offset) {
8930
50
  mjs_append_stack_trace_line(mjs, offset);
8931
100
  while (mjs->call_stack.len >=
8932
         sizeof(mjs_val_t) * CALL_STACK_FRAME_ITEMS_CNT) {
8933
    int i;
8934
8935
    /* set current offset to it to the offset stored in the frame */
8936
    offset = mjs_get_int(
8937
        mjs, *vptr(&mjs->call_stack, -1 - CALL_STACK_FRAME_ITEM_RETURN_ADDR));
8938
8939
    /* pop frame from the call stack */
8940
    for (i = 0; i < CALL_STACK_FRAME_ITEMS_CNT; i++) {
8941
      mjs_pop_val(&mjs->call_stack);
8942
    }
8943
8944
    mjs_append_stack_trace_line(mjs, offset);
8945
  }
8946
50
}
8947
8948
void mjs_own(struct mjs *mjs, mjs_val_t *v) {
8949
  mbuf_append(&mjs->owned_values, &v, sizeof(v));
8950
}
8951
8952
int mjs_disown(struct mjs *mjs, mjs_val_t *v) {
8953
  mjs_val_t **vp = (mjs_val_t **) (mjs->owned_values.buf +
8954
                                   mjs->owned_values.len - sizeof(v));
8955
8956
  for (; (char *) vp >= mjs->owned_values.buf; vp--) {
8957
    if (*vp == v) {
8958
      *vp = *(mjs_val_t **) (mjs->owned_values.buf + mjs->owned_values.len -
8959
                             sizeof(v));
8960
      mjs->owned_values.len -= sizeof(v);
8961
      return 1;
8962
    }
8963
  }
8964
8965
  return 0;
8966
}
8967
8968
/*
8969
 * Returns position in the data stack at which the called function is located,
8970
 * and which should be later replaced with the returned value.
8971
 */
8972
MJS_PRIVATE int mjs_getretvalpos(struct mjs *mjs) {
8973
  int pos;
8974
  mjs_val_t *ppos = vptr(&mjs->call_stack, -1);
8975
  // LOG(LL_INFO, ("ppos: %p %d", ppos, mjs_stack_size(&mjs->call_stack)));
8976
  assert(ppos != NULL && mjs_is_number(*ppos));
8977
  pos = mjs_get_int(mjs, *ppos) - 1;
8978
  assert(pos < (int) mjs_stack_size(&mjs->stack));
8979
  return pos;
8980
}
8981
8982
int mjs_nargs(struct mjs *mjs) {
8983
  int top = mjs_stack_size(&mjs->stack);
8984
  int pos = mjs_getretvalpos(mjs) + 1;
8985
  // LOG(LL_INFO, ("top: %d pos: %d", top, pos));
8986
  return pos > 0 && pos < top ? top - pos : 0;
8987
}
8988
8989
mjs_val_t mjs_arg(struct mjs *mjs, int arg_index) {
8990
  mjs_val_t res = MJS_UNDEFINED;
8991
  int top = mjs_stack_size(&mjs->stack);
8992
  int pos = mjs_getretvalpos(mjs) + 1;
8993
  // LOG(LL_INFO, ("idx %d pos: %d", arg_index, pos));
8994
  if (pos > 0 && pos + arg_index < top) {
8995
    res = *vptr(&mjs->stack, pos + arg_index);
8996
  }
8997
  return res;
8998
}
8999
9000
void mjs_return(struct mjs *mjs, mjs_val_t v) {
9001
  int pos = mjs_getretvalpos(mjs);
9002
  // LOG(LL_INFO, ("pos: %d", pos));
9003
  mjs->stack.len = sizeof(mjs_val_t) * pos;
9004
  mjs_push(mjs, v);
9005
}
9006
9007
41
MJS_PRIVATE mjs_val_t vtop(struct mbuf *m) {
9008
41
  size_t size = mjs_stack_size(m);
9009
41
  return size > 0 ? *vptr(m, size - 1) : MJS_UNDEFINED;
9010
}
9011
9012
167
MJS_PRIVATE size_t mjs_stack_size(const struct mbuf *m) {
9013
167
  return m->len / sizeof(mjs_val_t);
9014
}
9015
9016
81
MJS_PRIVATE mjs_val_t *vptr(struct mbuf *m, int idx) {
9017
81
  int size = mjs_stack_size(m);
9018
81
  if (idx < 0) idx = size + idx;
9019

81
  return idx >= 0 && idx < size ? &((mjs_val_t *) m->buf)[idx] : NULL;
9020
}
9021
9022
105
MJS_PRIVATE mjs_val_t mjs_pop(struct mjs *mjs) {
9023
105
  if (mjs->stack.len == 0) {
9024
    mjs_set_errorf(mjs, MJS_INTERNAL_ERROR, "stack underflow");
9025
    return MJS_UNDEFINED;
9026
  } else {
9027
105
    return mjs_pop_val(&mjs->stack);
9028
  }
9029
}
9030
9031
273
MJS_PRIVATE void push_mjs_val(struct mbuf *m, mjs_val_t v) {
9032
273
  mbuf_append(m, &v, sizeof(v));
9033
273
}
9034
9035
105
MJS_PRIVATE mjs_val_t mjs_pop_val(struct mbuf *m) {
9036
105
  mjs_val_t v = MJS_UNDEFINED;
9037
105
  assert(m->len >= sizeof(v));
9038
105
  if (m->len >= sizeof(v)) {
9039
105
    memcpy(&v, m->buf + m->len - sizeof(v), sizeof(v));
9040
105
    m->len -= sizeof(v);
9041
  }
9042
105
  return v;
9043
}
9044
9045
195
MJS_PRIVATE void mjs_push(struct mjs *mjs, mjs_val_t v) {
9046
195
  push_mjs_val(&mjs->stack, v);
9047
195
}
9048
9049
void mjs_set_generate_jsc(struct mjs *mjs, int generate_jsc) {
9050
  mjs->generate_jsc = generate_jsc;
9051
}
9052
#ifdef MJS_MODULE_LINES
9053
#line 1 "mjs/src/mjs_dataview.c"
9054
#endif
9055
/*
9056
 * Copyright (c) 2017 Cesanta Software Limited
9057
 * All rights reserved
9058
 */
9059
9060
/* Amalgamated: #include "mjs/src/mjs_exec_public.h" */
9061
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
9062
/* Amalgamated: #include "mjs/src/mjs_object.h" */
9063
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
9064
/* Amalgamated: #include "mjs/src/mjs_util.h" */
9065
9066
void *mjs_mem_to_ptr(unsigned val) {
9067
  return (void *) (uintptr_t) val;
9068
}
9069
9070
void *mjs_mem_get_ptr(void *base, int offset) {
9071
  return (char *) base + offset;
9072
}
9073
9074
void mjs_mem_set_ptr(void *ptr, void *val) {
9075
  *(void **) ptr = val;
9076
}
9077
9078
double mjs_mem_get_dbl(void *ptr) {
9079
  double v;
9080
  memcpy(&v, ptr, sizeof(v));
9081
  return v;
9082
}
9083
9084
void mjs_mem_set_dbl(void *ptr, double val) {
9085
  memcpy(ptr, &val, sizeof(val));
9086
}
9087
9088
/*
9089
 * TODO(dfrank): add support for unsigned ints to ffi and use
9090
 * unsigned int here
9091
 */
9092
double mjs_mem_get_uint(void *ptr, int size, int bigendian) {
9093
  uint8_t *p = (uint8_t *) ptr;
9094
  int i, inc = bigendian ? 1 : -1;
9095
  unsigned int res = 0;
9096
  p += bigendian ? 0 : size - 1;
9097
  for (i = 0; i < size; i++, p += inc) {
9098
    res <<= 8;
9099
    res |= *p;
9100
  }
9101
  return res;
9102
}
9103
9104
/*
9105
 * TODO(dfrank): add support for unsigned ints to ffi and use
9106
 * unsigned int here
9107
 */
9108
double mjs_mem_get_int(void *ptr, int size, int bigendian) {
9109
  uint8_t *p = (uint8_t *) ptr;
9110
  int i, inc = bigendian ? 1 : -1;
9111
  int res = 0;
9112
  p += bigendian ? 0 : size - 1;
9113
9114
  for (i = 0; i < size; i++, p += inc) {
9115
    res <<= 8;
9116
    res |= *p;
9117
  }
9118
9119
  /* sign-extend */
9120
  {
9121
    int extra = sizeof(res) - size;
9122
    for (i = 0; i < extra; i++) res <<= 8;
9123
    for (i = 0; i < extra; i++) res >>= 8;
9124
  }
9125
9126
  return res;
9127
}
9128
9129
void mjs_mem_set_uint(void *ptr, unsigned int val, int size, int bigendian) {
9130
  uint8_t *p = (uint8_t *) ptr + (bigendian ? size - 1 : 0);
9131
  int i, inc = bigendian ? -1 : 1;
9132
  for (i = 0; i < size; i++, p += inc) {
9133
    *p = val & 0xff;
9134
    val >>= 8;
9135
  }
9136
}
9137
9138
void mjs_mem_set_int(void *ptr, int val, int size, int bigendian) {
9139
  mjs_mem_set_uint(ptr, val, size, bigendian);
9140
}
9141
#ifdef MJS_MODULE_LINES
9142
#line 1 "mjs/src/mjs_exec.c"
9143
#endif
9144
/*
9145
 * Copyright (c) 2017 Cesanta Software Limited
9146
 * All rights reserved
9147
 */
9148
9149
/* Amalgamated: #include "common/cs_file.h" */
9150
/* Amalgamated: #include "common/cs_varint.h" */
9151
9152
/* Amalgamated: #include "mjs/src/mjs_array.h" */
9153
/* Amalgamated: #include "mjs/src/mjs_bcode.h" */
9154
/* Amalgamated: #include "mjs/src/mjs_conversion.h" */
9155
/* Amalgamated: #include "mjs/src/mjs_core.h" */
9156
/* Amalgamated: #include "mjs/src/mjs_exec.h" */
9157
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
9158
/* Amalgamated: #include "mjs/src/mjs_object.h" */
9159
/* Amalgamated: #include "mjs/src/mjs_parser.h" */
9160
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
9161
/* Amalgamated: #include "mjs/src/mjs_string.h" */
9162
/* Amalgamated: #include "mjs/src/mjs_tok.h" */
9163
/* Amalgamated: #include "mjs/src/mjs_util.h" */
9164
9165
#if MJS_GENERATE_JSC && defined(CS_MMAP)
9166
#include <sys/mman.h>
9167
#endif
9168
9169
/*
9170
 * Pushes call stack frame. Offset is a global bcode offset. Retval_stack_idx
9171
 * is an index in mjs->stack at which return value should be written later.
9172
 */
9173
static void call_stack_push_frame(struct mjs *mjs, size_t offset,
9174
                                  mjs_val_t retval_stack_idx) {
9175
  /* Pop `this` value, and apply it */
9176
  mjs_val_t this_obj = mjs_pop_val(&mjs->arg_stack);
9177
9178
  /*
9179
   * NOTE: the layout is described by enum mjs_call_stack_frame_item
9180
   */
9181
  push_mjs_val(&mjs->call_stack, mjs->vals.this_obj);
9182
  mjs->vals.this_obj = this_obj;
9183
9184
  push_mjs_val(&mjs->call_stack, mjs_mk_number(mjs, (double) offset));
9185
  push_mjs_val(&mjs->call_stack,
9186
               mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->scopes)));
9187
  push_mjs_val(
9188
      &mjs->call_stack,
9189
      mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->loop_addresses)));
9190
  push_mjs_val(&mjs->call_stack, retval_stack_idx);
9191
}
9192
9193
/*
9194
 * Restores call stack frame. Returns the return address.
9195
 */
9196
static size_t call_stack_restore_frame(struct mjs *mjs) {
9197
  size_t retval_stack_idx, return_address, scope_index, loop_addr_index;
9198
  assert(mjs_stack_size(&mjs->call_stack) >= CALL_STACK_FRAME_ITEMS_CNT);
9199
9200
  /*
9201
   * NOTE: the layout is described by enum mjs_call_stack_frame_item
9202
   */
9203
  retval_stack_idx = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack));
9204
  loop_addr_index = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack));
9205
  scope_index = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack));
9206
  return_address = mjs_get_int(mjs, mjs_pop_val(&mjs->call_stack));
9207
  mjs->vals.this_obj = mjs_pop_val(&mjs->call_stack);
9208
9209
  /* Remove created scopes */
9210
  while (mjs_stack_size(&mjs->scopes) > scope_index) {
9211
    mjs_pop_val(&mjs->scopes);
9212
  }
9213
9214
  /* Remove loop addresses */
9215
  while (mjs_stack_size(&mjs->loop_addresses) > loop_addr_index) {
9216
    mjs_pop_val(&mjs->loop_addresses);
9217
  }
9218
9219
  /* Shrink stack, leave return value on top */
9220
  mjs->stack.len = retval_stack_idx * sizeof(mjs_val_t);
9221
9222
  /* Jump to the return address */
9223
  return return_address;
9224
}
9225
9226
40
static mjs_val_t mjs_find_scope(struct mjs *mjs, mjs_val_t key) {
9227
40
  size_t num_scopes = mjs_stack_size(&mjs->scopes);
9228
40
  while (num_scopes > 0) {
9229
40
    mjs_val_t scope = *vptr(&mjs->scopes, num_scopes - 1);
9230
40
    num_scopes--;
9231
40
    if (mjs_get_own_property_v(mjs, scope, key) != NULL) return scope;
9232
  }
9233
40
  mjs_set_errorf(mjs, MJS_REFERENCE_ERROR, "[%s] is not defined",
9234
                 mjs_get_cstring(mjs, &key));
9235
40
  return MJS_UNDEFINED;
9236
}
9237
9238
mjs_val_t mjs_get_this(struct mjs *mjs) {
9239
  return mjs->vals.this_obj;
9240
}
9241
9242
4
static double do_arith_op(double da, double db, int op, bool *resnan) {
9243
4
  *resnan = false;
9244
9245

4
  if (isnan(da) || isnan(db)) {
9246
    *resnan = true;
9247
    return 0;
9248
  }
9249
  /* clang-format off */
9250



4
  switch (op) {
9251
    case TOK_MINUS:   return da - db;
9252
    case TOK_PLUS:    return da + db;
9253
    case TOK_MUL:     return da * db;
9254
    case TOK_DIV:
9255
2
      if (db != 0) {
9256
2
        return da / db;
9257
      } else {
9258
        /* TODO(dfrank): add support for Infinity and return it here */
9259
        *resnan = true;
9260
        return 0;
9261
      }
9262
    case TOK_REM:
9263
      /*
9264
       * TODO(dfrank): probably support remainder operation as it is in JS
9265
       * (which works with non-integer divisor).
9266
       */
9267
      db = (int) db;
9268
      if (db != 0) {
9269
        bool neg = false;
9270
        if (da < 0) {
9271
          neg = true;
9272
          da = -da;
9273
        }
9274
        if (db < 0) {
9275
          db = -db;
9276
        }
9277
        da = (double) ((int64_t) da % (int64_t) db);
9278
        if (neg) {
9279
          da = -da;
9280
        }
9281
        return da;
9282
      } else {
9283
        *resnan = true;
9284
        return 0;
9285
      }
9286
    case TOK_AND:     return (double) ((int64_t) da & (int64_t) db);
9287
2
    case TOK_OR:      return (double) ((int64_t) da | (int64_t) db);
9288
    case TOK_XOR:     return (double) ((int64_t) da ^ (int64_t) db);
9289
    case TOK_LSHIFT:  return (double) ((int64_t) da << (int64_t) db);
9290
    case TOK_RSHIFT:  return (double) ((int64_t) da >> (int64_t) db);
9291
    case TOK_URSHIFT: return (double) ((uint32_t) da >> (uint32_t) db);
9292
  }
9293
  /* clang-format on */
9294
  *resnan = true;
9295
  return 0;
9296
}
9297
9298
4
static void set_no_autoconversion_error(struct mjs *mjs) {
9299
4
  mjs_prepend_errorf(mjs, MJS_TYPE_ERROR,
9300
                     "implicit type conversion is prohibited");
9301
4
}
9302
9303
8
static mjs_val_t do_op(struct mjs *mjs, mjs_val_t a, mjs_val_t b, int op) {
9304
8
  mjs_val_t ret = MJS_UNDEFINED;
9305
8
  bool resnan = false;
9306

15
  if ((mjs_is_foreign(a) || mjs_is_number(a)) &&
9307
18
      (mjs_is_foreign(b) || mjs_is_number(b))) {
9308
4
    int is_result_ptr = 0;
9309
    double da, db, result;
9310
9311

4
    if (mjs_is_foreign(a) && mjs_is_foreign(b)) {
9312
      /* When two operands are pointers, only subtraction is supported */
9313
      if (op != TOK_MINUS) {
9314
        mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "invalid operands");
9315
      }
9316

4
    } else if (mjs_is_foreign(a) || mjs_is_foreign(b)) {
9317
      /*
9318
       * When one of the operands is a pointer, only + and - are supported,
9319
       * and the result is a pointer.
9320
       */
9321
      if (op != TOK_MINUS && op != TOK_PLUS) {
9322
        mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "invalid operands");
9323
      }
9324
      is_result_ptr = 1;
9325
    }
9326
8
    da = mjs_is_number(a) ? mjs_get_double(mjs, a)
9327
4
                          : (double) (uintptr_t) mjs_get_ptr(mjs, a);
9328
8
    db = mjs_is_number(b) ? mjs_get_double(mjs, b)
9329
4
                          : (double) (uintptr_t) mjs_get_ptr(mjs, b);
9330
4
    result = do_arith_op(da, db, op, &resnan);
9331
4
    if (resnan) {
9332
      ret = MJS_TAG_NAN;
9333
    } else {
9334
      /*
9335
       * If at least one of the operands was a pointer, result should also be
9336
       * a pointer
9337
       */
9338
4
      ret = is_result_ptr ? mjs_mk_foreign(mjs, (void *) (uintptr_t) result)
9339
4
                          : mjs_mk_number(mjs, result);
9340
    }
9341

4
  } else if (mjs_is_string(a) && mjs_is_string(b) && (op == TOK_PLUS)) {
9342
    ret = s_concat(mjs, a, b);
9343
  } else {
9344
4
    set_no_autoconversion_error(mjs);
9345
  }
9346
8
  return ret;
9347
}
9348
9349
static void op_assign(struct mjs *mjs, int op) {
9350
  mjs_val_t val = mjs_pop(mjs);
9351
  mjs_val_t obj = mjs_pop(mjs);
9352
  mjs_val_t key = mjs_pop(mjs);
9353
  if (mjs_is_object(obj) && mjs_is_string(key)) {
9354
    mjs_val_t v = mjs_get_v(mjs, obj, key);
9355
    mjs_set_v(mjs, obj, key, do_op(mjs, v, val, op));
9356
    mjs_push(mjs, v);
9357
  } else {
9358
    mjs_set_errorf(mjs, MJS_TYPE_ERROR, "invalid operand");
9359
  }
9360
}
9361
9362
static int check_equal(struct mjs *mjs, mjs_val_t a, mjs_val_t b) {
9363
  int ret = 0;
9364
  if (a == MJS_TAG_NAN && b == MJS_TAG_NAN) {
9365
    ret = 0;
9366
  } else if (a == b) {
9367
    ret = 1;
9368
  } else if (mjs_is_number(a) && mjs_is_number(b)) {
9369
    /*
9370
     * The case of equal numbers is handled above, so here the result is always
9371
     * false
9372
     */
9373
    ret = 0;
9374
  } else if (mjs_is_string(a) && mjs_is_string(b)) {
9375
    ret = s_cmp(mjs, a, b) == 0;
9376
  } else if (mjs_is_foreign(a) && b == MJS_NULL) {
9377
    ret = mjs_get_ptr(mjs, a) == NULL;
9378
  } else if (a == MJS_NULL && mjs_is_foreign(b)) {
9379
    ret = mjs_get_ptr(mjs, b) == NULL;
9380
  } else {
9381
    ret = 0;
9382
  }
9383
  return ret;
9384
}
9385
9386
13
static void exec_expr(struct mjs *mjs, int op) {
9387








13
  switch (op) {
9388
    case TOK_DOT:
9389
      break;
9390
    case TOK_MINUS:
9391
    case TOK_PLUS:
9392
    case TOK_MUL:
9393
    case TOK_DIV:
9394
    case TOK_REM:
9395
    case TOK_XOR:
9396
    case TOK_AND:
9397
    case TOK_OR:
9398
    case TOK_LSHIFT:
9399
    case TOK_RSHIFT:
9400
    case TOK_URSHIFT: {
9401
8
      mjs_val_t b = mjs_pop(mjs);
9402
8
      mjs_val_t a = mjs_pop(mjs);
9403
8
      mjs_push(mjs, do_op(mjs, a, b, op));
9404
8
      break;
9405
    }
9406
    case TOK_UNARY_MINUS: {
9407
2
      double a = mjs_get_double(mjs, mjs_pop(mjs));
9408
2
      mjs_push(mjs, mjs_mk_number(mjs, -a));
9409
2
      break;
9410
    }
9411
    case TOK_NOT: {
9412
      mjs_val_t val = mjs_pop(mjs);
9413
      mjs_push(mjs, mjs_mk_boolean(mjs, !mjs_is_truthy(mjs, val)));
9414
      break;
9415
    }
9416
    case TOK_TILDA: {
9417
      double a = mjs_get_double(mjs, mjs_pop(mjs));
9418
      mjs_push(mjs, mjs_mk_number(mjs, (double) (~(int64_t) a)));
9419
      break;
9420
    }
9421
    case TOK_UNARY_PLUS:
9422
      break;
9423
    case TOK_EQ:
9424
      mjs_set_errorf(mjs, MJS_NOT_IMPLEMENTED_ERROR, "Use ===, not ==");
9425
      break;
9426
    case TOK_NE:
9427
      mjs_set_errorf(mjs, MJS_NOT_IMPLEMENTED_ERROR, "Use !==, not !=");
9428
      break;
9429
    case TOK_EQ_EQ: {
9430
      mjs_val_t a = mjs_pop(mjs);
9431
      mjs_val_t b = mjs_pop(mjs);
9432
      mjs_push(mjs, mjs_mk_boolean(mjs, check_equal(mjs, a, b)));
9433
      break;
9434
    }
9435
    case TOK_NE_NE: {
9436
      mjs_val_t a = mjs_pop(mjs);
9437
      mjs_val_t b = mjs_pop(mjs);
9438
      mjs_push(mjs, mjs_mk_boolean(mjs, !check_equal(mjs, a, b)));
9439
      break;
9440
    }
9441
    case TOK_LT: {
9442
      double b = mjs_get_double(mjs, mjs_pop(mjs));
9443
      double a = mjs_get_double(mjs, mjs_pop(mjs));
9444
      mjs_push(mjs, mjs_mk_boolean(mjs, a < b));
9445
      break;
9446
    }
9447
    case TOK_GT: {
9448
      double b = mjs_get_double(mjs, mjs_pop(mjs));
9449
      double a = mjs_get_double(mjs, mjs_pop(mjs));
9450
      mjs_push(mjs, mjs_mk_boolean(mjs, a > b));
9451
      break;
9452
    }
9453
    case TOK_LE: {
9454
      double b = mjs_get_double(mjs, mjs_pop(mjs));
9455
      double a = mjs_get_double(mjs, mjs_pop(mjs));
9456
      mjs_push(mjs, mjs_mk_boolean(mjs, a <= b));
9457
      break;
9458
    }
9459
    case TOK_GE: {
9460
      double b = mjs_get_double(mjs, mjs_pop(mjs));
9461
      double a = mjs_get_double(mjs, mjs_pop(mjs));
9462
      mjs_push(mjs, mjs_mk_boolean(mjs, a >= b));
9463
      break;
9464
    }
9465
    case TOK_ASSIGN: {
9466
      mjs_val_t val = mjs_pop(mjs);
9467
      mjs_val_t obj = mjs_pop(mjs);
9468
      mjs_val_t key = mjs_pop(mjs);
9469
      if (mjs_is_object(obj)) {
9470
        mjs_set_v(mjs, obj, key, val);
9471
      } else if (mjs_is_foreign(obj)) {
9472
        /*
9473
         * We don't have setters, so in order to support properties which behave
9474
         * like setters, we have to parse key right here, instead of having real
9475
         * built-in prototype objects
9476
         */
9477
9478
        int ikey = mjs_get_int(mjs, key);
9479
        int ival = mjs_get_int(mjs, val);
9480
9481
        if (!mjs_is_number(key)) {
9482
          mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "index must be a number");
9483
          val = MJS_UNDEFINED;
9484
        } else if (!mjs_is_number(val) || ival < 0 || ival > 0xff) {
9485
          mjs_prepend_errorf(mjs, MJS_TYPE_ERROR,
9486
                             "only number 0 .. 255 can be assigned");
9487
          val = MJS_UNDEFINED;
9488
        } else {
9489
          uint8_t *ptr = (uint8_t *) mjs_get_ptr(mjs, obj);
9490
          *(ptr + ikey) = (uint8_t) ival;
9491
        }
9492
      } else {
9493
        mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "unsupported object type");
9494
      }
9495
      mjs_push(mjs, val);
9496
      break;
9497
    }
9498
    case TOK_POSTFIX_PLUS: {
9499
      mjs_val_t obj = mjs_pop(mjs);
9500
      mjs_val_t key = mjs_pop(mjs);
9501
      if (mjs_is_object(obj) && mjs_is_string(key)) {
9502
        mjs_val_t v = mjs_get_v(mjs, obj, key);
9503
        mjs_val_t v1 = do_op(mjs, v, mjs_mk_number(mjs, 1), TOK_PLUS);
9504
        mjs_set_v(mjs, obj, key, v1);
9505
        mjs_push(mjs, v);
9506
      } else {
9507
        mjs_set_errorf(mjs, MJS_TYPE_ERROR, "invalid operand for ++");
9508
      }
9509
      break;
9510
    }
9511
    case TOK_POSTFIX_MINUS: {
9512
      mjs_val_t obj = mjs_pop(mjs);
9513
      mjs_val_t key = mjs_pop(mjs);
9514
      if (mjs_is_object(obj) && mjs_is_string(key)) {
9515
        mjs_val_t v = mjs_get_v(mjs, obj, key);
9516
        mjs_val_t v1 = do_op(mjs, v, mjs_mk_number(mjs, 1), TOK_MINUS);
9517
        mjs_set_v(mjs, obj, key, v1);
9518
        mjs_push(mjs, v);
9519
      } else {
9520
        mjs_set_errorf(mjs, MJS_TYPE_ERROR, "invalid operand for --");
9521
      }
9522
      break;
9523
    }
9524
    case TOK_MINUS_MINUS: {
9525
2
      mjs_val_t obj = mjs_pop(mjs);
9526
2
      mjs_val_t key = mjs_pop(mjs);
9527

2
      if (mjs_is_object(obj) && mjs_is_string(key)) {
9528
        mjs_val_t v = mjs_get_v(mjs, obj, key);
9529
        v = do_op(mjs, v, mjs_mk_number(mjs, 1), TOK_MINUS);
9530
        mjs_set_v(mjs, obj, key, v);
9531
        mjs_push(mjs, v);
9532
      } else {
9533
2
        mjs_set_errorf(mjs, MJS_TYPE_ERROR, "invalid operand for --");
9534
      }
9535
2
      break;
9536
    }
9537
    case TOK_PLUS_PLUS: {
9538
      mjs_val_t obj = mjs_pop(mjs);
9539
      mjs_val_t key = mjs_pop(mjs);
9540
      if (mjs_is_object(obj) && mjs_is_string(key)) {
9541
        mjs_val_t v = mjs_get_v(mjs, obj, key);
9542
        v = do_op(mjs, v, mjs_mk_number(mjs, 1), TOK_PLUS);
9543
        mjs_set_v(mjs, obj, key, v);
9544
        mjs_push(mjs, v);
9545
      } else {
9546
        mjs_set_errorf(mjs, MJS_TYPE_ERROR, "invalid operand for ++");
9547
      }
9548
      break;
9549
    }
9550
    /*
9551
     * NOTE: TOK_LOGICAL_AND and TOK_LOGICAL_OR don't need to be here, because
9552
     * they are just naturally handled by the short-circuit evaluation.
9553
     * See PARSE_LTR_BINOP() macro in mjs_parser.c.
9554
     */
9555
9556
    /* clang-format off */
9557
    case TOK_MINUS_ASSIGN:    op_assign(mjs, TOK_MINUS);    break;
9558
    case TOK_PLUS_ASSIGN:     op_assign(mjs, TOK_PLUS);     break;
9559
    case TOK_MUL_ASSIGN:      op_assign(mjs, TOK_MUL);      break;
9560
    case TOK_DIV_ASSIGN:      op_assign(mjs, TOK_DIV);      break;
9561
    case TOK_REM_ASSIGN:      op_assign(mjs, TOK_REM);      break;
9562
    case TOK_AND_ASSIGN:      op_assign(mjs, TOK_AND);      break;
9563
    case TOK_OR_ASSIGN:       op_assign(mjs, TOK_OR);       break;
9564
    case TOK_XOR_ASSIGN:      op_assign(mjs, TOK_XOR);      break;
9565
    case TOK_LSHIFT_ASSIGN:   op_assign(mjs, TOK_LSHIFT);   break;
9566
    case TOK_RSHIFT_ASSIGN:   op_assign(mjs, TOK_RSHIFT);   break;
9567
    case TOK_URSHIFT_ASSIGN:  op_assign(mjs, TOK_URSHIFT);  break;
9568
    case TOK_COMMA: break;
9569
    /* clang-format on */
9570
    case TOK_KEYWORD_TYPEOF:
9571
1
      mjs_push(mjs, mjs_mk_string(mjs, mjs_typeof(mjs_pop(mjs)), ~0, 1));
9572
1
      break;
9573
    default:
9574
      LOG(LL_ERROR, ("Unknown expr: %d", op));
9575
      break;
9576
  }
9577
13
}
9578
9579
static int getprop_builtin_string(struct mjs *mjs, mjs_val_t val,
9580
                                  const char *name, size_t name_len,
9581
                                  mjs_val_t *res) {
9582
  int isnum = 0;
9583
  int idx = cstr_to_ulong(name, name_len, &isnum);
9584
9585
  if (strcmp(name, "length") == 0) {
9586
    size_t val_len;
9587
    mjs_get_string(mjs, &val, &val_len);
9588
    *res = mjs_mk_number(mjs, (double) val_len);
9589
    return 1;
9590
  } else if (strcmp(name, "at") == 0 || strcmp(name, "charCodeAt") == 0) {
9591
    *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_string_char_code_at);
9592
    return 1;
9593
  } else if (strcmp(name, "indexOf") == 0) {
9594
    *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_string_index_of);
9595
    return 1;
9596
  } else if (strcmp(name, "slice") == 0) {
9597
    *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_string_slice);
9598
    return 1;
9599
  } else if (isnum) {
9600
    /*
9601
     * string subscript: return a new one-byte string if the index
9602
     * is not out of bounds
9603
     */
9604
    size_t val_len;
9605
    const char *str = mjs_get_string(mjs, &val, &val_len);
9606
    if (idx >= 0 && idx < (int) val_len) {
9607
      *res = mjs_mk_string(mjs, str + idx, 1, 1);
9608
    } else {
9609
      *res = MJS_UNDEFINED;
9610
    }
9611
    return 1;
9612
  }
9613
  return 0;
9614
}
9615
9616
static int getprop_builtin_array(struct mjs *mjs, mjs_val_t val,
9617
                                 const char *name, size_t name_len,
9618
                                 mjs_val_t *res) {
9619
  if (strcmp(name, "splice") == 0) {
9620
    *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_array_splice);
9621
    return 1;
9622
  } else if (strcmp(name, "push") == 0) {
9623
    *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_array_push_internal);
9624
    return 1;
9625
  } else if (strcmp(name, "length") == 0) {
9626
    *res = mjs_mk_number(mjs, mjs_array_length(mjs, val));
9627
    return 1;
9628
  }
9629
9630
  (void) name_len;
9631
  return 0;
9632
}
9633
9634
static int getprop_builtin_foreign(struct mjs *mjs, mjs_val_t val,
9635
                                   const char *name, size_t name_len,
9636
                                   mjs_val_t *res) {
9637
  int isnum = 0;
9638
  int idx = cstr_to_ulong(name, name_len, &isnum);
9639
9640
  if (!isnum) {
9641
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "index must be a number");
9642
  } else {
9643
    uint8_t *ptr = (uint8_t *) mjs_get_ptr(mjs, val);
9644
    *res = mjs_mk_number(mjs, *(ptr + idx));
9645
  }
9646
  return 1;
9647
}
9648
9649
static void mjs_apply_(struct mjs *mjs) {
9650
  mjs_val_t res = MJS_UNDEFINED, *args = NULL;
9651
  mjs_val_t func = mjs->vals.this_obj, v = mjs_arg(mjs, 1);
9652
  int i, nargs = 0;
9653
  if (mjs_is_array(v)) {
9654
    nargs = mjs_array_length(mjs, v);
9655
    args = calloc(nargs, sizeof(args[0]));
9656
    for (i = 0; i < nargs; i++) args[i] = mjs_array_get(mjs, v, i);
9657
  }
9658
  mjs_apply(mjs, &res, func, mjs_arg(mjs, 0), nargs, args);
9659
  free(args);
9660
  mjs_return(mjs, res);
9661
}
9662
9663
static int getprop_builtin(struct mjs *mjs, mjs_val_t val, mjs_val_t name,
9664
                           mjs_val_t *res) {
9665
  size_t n;
9666
  char *s = NULL;
9667
  int need_free = 0;
9668
  int handled = 0;
9669
9670
  mjs_err_t err = mjs_to_string(mjs, &name, &s, &n, &need_free);
9671
9672
  if (err == MJS_OK) {
9673
    if (mjs_is_string(val)) {
9674
      handled = getprop_builtin_string(mjs, val, s, n, res);
9675
    } else if (s != NULL && n == 5 && strncmp(s, "apply", n) == 0) {
9676
      *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) mjs_apply_);
9677
      handled = 1;
9678
    } else if (mjs_is_array(val)) {
9679
      handled = getprop_builtin_array(mjs, val, s, n, res);
9680
    } else if (mjs_is_foreign(val)) {
9681
      handled = getprop_builtin_foreign(mjs, val, s, n, res);
9682
    }
9683
  }
9684
9685
  if (need_free) {
9686
    free(s);
9687
    s = NULL;
9688
  }
9689
9690
  return handled;
9691
}
9692
9693
66
MJS_PRIVATE mjs_err_t mjs_execute(struct mjs *mjs, size_t off, mjs_val_t *res) {
9694
  size_t i;
9695
66
  uint8_t prev_opcode = OP_MAX;
9696
66
  uint8_t opcode = OP_MAX;
9697
9698
  /*
9699
   * remember lengths of all stacks, they will be restored in case of an error
9700
   */
9701
66
  int stack_len = mjs->stack.len;
9702
66
  int call_stack_len = mjs->call_stack.len;
9703
66
  int arg_stack_len = mjs->arg_stack.len;
9704
66
  int scopes_len = mjs->scopes.len;
9705
66
  int loop_addresses_len = mjs->loop_addresses.len;
9706
66
  size_t start_off = off;
9707
  const uint8_t *code;
9708
9709
66
  struct mjs_bcode_part bp = *mjs_bcode_part_get_by_offset(mjs, off);
9710
9711
66
  mjs_set_errorf(mjs, MJS_OK, NULL);
9712
66
  free(mjs->stack_trace);
9713
66
  mjs->stack_trace = NULL;
9714
9715
66
  off -= bp.start_idx;
9716
9717
264
  for (i = off; i < bp.data.len; i++) {
9718
248
    mjs->cur_bcode_offset = i;
9719
9720
248
    if (mjs->need_gc) {
9721
67
      if (maybe_gc(mjs)) {
9722
67
        mjs->need_gc = 0;
9723
      }
9724
    }
9725
#if MJS_AGGRESSIVE_GC
9726
    maybe_gc(mjs);
9727
#endif
9728
9729
248
    code = (const uint8_t *) bp.data.p;
9730
248
    mjs_disasm_single(code, i);
9731
248
    prev_opcode = opcode;
9732
248
    opcode = code[i];
9733









248
    switch (opcode) {
9734
      case OP_BCODE_HEADER: {
9735
        mjs_header_item_t bcode_offset;
9736
66
        memcpy(&bcode_offset,
9737
66
               code + i + 1 +
9738
                   sizeof(mjs_header_item_t) * MJS_HDR_ITEM_BCODE_OFFSET,
9739
               sizeof(bcode_offset));
9740
66
        i += bcode_offset;
9741
66
      } break;
9742
      case OP_PUSH_NULL:
9743
2
        mjs_push(mjs, mjs_mk_null());
9744
2
        break;
9745
      case OP_PUSH_UNDEF:
9746
5
        mjs_push(mjs, mjs_mk_undefined());
9747
5
        break;
9748
      case OP_PUSH_FALSE:
9749
2
        mjs_push(mjs, mjs_mk_boolean(mjs, 0));
9750
2
        break;
9751
      case OP_PUSH_TRUE:
9752
1
        mjs_push(mjs, mjs_mk_boolean(mjs, 1));
9753
1
        break;
9754
      case OP_PUSH_OBJ:
9755
1
        mjs_push(mjs, mjs_mk_object(mjs));
9756
1
        break;
9757
      case OP_PUSH_ARRAY:
9758
        mjs_push(mjs, mjs_mk_array(mjs));
9759
        break;
9760
      case OP_PUSH_FUNC: {
9761
        int llen, n = cs_varint_decode_unsafe(&code[i + 1], &llen);
9762
        mjs_push(mjs, mjs_mk_function(mjs, bp.start_idx + i - n));
9763
        i += llen;
9764
        break;
9765
      }
9766
      case OP_PUSH_THIS:
9767
1
        mjs_push(mjs, mjs->vals.this_obj);
9768
1
        break;
9769
      case OP_JMP: {
9770
        int llen, n = cs_varint_decode_unsafe(&code[i + 1], &llen);
9771
        i += n + llen;
9772
        break;
9773
      }
9774
      case OP_JMP_FALSE: {
9775
        int llen, n = cs_varint_decode_unsafe(&code[i + 1], &llen);
9776
        i += llen;
9777
        if (!mjs_is_truthy(mjs, mjs_pop(mjs))) {
9778
          mjs_push(mjs, MJS_UNDEFINED);
9779
          i += n;
9780
        }
9781
        break;
9782
      }
9783
      /*
9784
       * OP_JMP_NEUTRAL_... ops are like as OP_JMP_..., but they are completely
9785
       * stack-neutral: they just check the TOS, and increment instruction
9786
       * pointer if the TOS is truthy/falsy.
9787
       */
9788
      case OP_JMP_NEUTRAL_TRUE: {
9789
        int llen, n = cs_varint_decode_unsafe(&code[i + 1], &llen);
9790
        i += llen;
9791
        if (mjs_is_truthy(mjs, vtop(&mjs->stack))) {
9792
          i += n;
9793
        }
9794
        break;
9795
      }
9796
      case OP_JMP_NEUTRAL_FALSE: {
9797
        int llen, n = cs_varint_decode_unsafe(&code[i + 1], &llen);
9798
        i += llen;
9799
        if (!mjs_is_truthy(mjs, vtop(&mjs->stack))) {
9800
          i += n;
9801
        }
9802
        break;
9803
      }
9804
      case OP_FIND_SCOPE: {
9805
40
        mjs_val_t key = vtop(&mjs->stack);
9806
40
        mjs_push(mjs, mjs_find_scope(mjs, key));
9807
40
        break;
9808
      }
9809
      case OP_CREATE: {
9810
1
        mjs_val_t obj = mjs_pop(mjs);
9811
1
        mjs_val_t key = mjs_pop(mjs);
9812
1
        if (mjs_get_own_property_v(mjs, obj, key) == NULL) {
9813
1
          mjs_set_v(mjs, obj, key, MJS_UNDEFINED);
9814
        }
9815
1
        break;
9816
      }
9817
      case OP_APPEND: {
9818
        mjs_val_t val = mjs_pop(mjs);
9819
        mjs_val_t arr = mjs_pop(mjs);
9820
        mjs_err_t err = mjs_array_push(mjs, arr, val);
9821
        if (err != MJS_OK) {
9822
          mjs_set_errorf(mjs, MJS_TYPE_ERROR, "append to non-array");
9823
        }
9824
        break;
9825
      }
9826
      case OP_GET: {
9827
        mjs_val_t obj = mjs_pop(mjs);
9828
        mjs_val_t key = mjs_pop(mjs);
9829
        mjs_val_t val = MJS_UNDEFINED;
9830
9831
        if (!getprop_builtin(mjs, obj, key, &val)) {
9832
          if (mjs_is_object(obj)) {
9833
            val = mjs_get_v_proto(mjs, obj, key);
9834
          } else {
9835
            mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "type error");
9836
          }
9837
        }
9838
9839
        mjs_push(mjs, val);
9840
        if (prev_opcode != OP_FIND_SCOPE) {
9841
          /*
9842
           * Previous opcode was not OP_FIND_SCOPE, so it's some "custom"
9843
           * object which might be used as `this`, so, save it
9844
           */
9845
          mjs->vals.last_getprop_obj = obj;
9846
        } else {
9847
          /*
9848
           * Previous opcode was OP_FIND_SCOPE, so we're getting value from
9849
           * the scope, and it should *not* be used as `this`
9850
           */
9851
          mjs->vals.last_getprop_obj = MJS_UNDEFINED;
9852
        }
9853
        break;
9854
      }
9855
      case OP_DEL_SCOPE:
9856
        if (mjs->scopes.len <= 1) {
9857
          mjs_set_errorf(mjs, MJS_INTERNAL_ERROR, "scopes underflow");
9858
        } else {
9859
          mjs_pop_val(&mjs->scopes);
9860
        }
9861
        break;
9862
      case OP_NEW_SCOPE:
9863
        push_mjs_val(&mjs->scopes, mjs_mk_object(mjs));
9864
        break;
9865
      case OP_PUSH_SCOPE:
9866
1
        assert(mjs_stack_size(&mjs->scopes) > 0);
9867
1
        mjs_push(mjs, vtop(&mjs->scopes));
9868
1
        break;
9869
      case OP_PUSH_STR: {
9870
50
        int llen, n = cs_varint_decode_unsafe(&code[i + 1], &llen);
9871
50
        mjs_push(mjs, mjs_mk_string(mjs, (char *) code + i + 1 + llen, n, 1));
9872
50
        i += llen + n;
9873
50
        break;
9874
      }
9875
      case OP_PUSH_INT: {
9876
        int llen;
9877
31
        int64_t n = cs_varint_decode_unsafe(&code[i + 1], &llen);
9878
31
        mjs_push(mjs, mjs_mk_number(mjs, (double) n));
9879
31
        i += llen;
9880
31
        break;
9881
      }
9882
      case OP_PUSH_DBL: {
9883
        int llen, n = cs_varint_decode_unsafe(&code[i + 1], &llen);
9884
        mjs_push(mjs, mjs_mk_number(
9885
                          mjs, strtod((char *) code + i + 1 + llen, NULL)));
9886
        i += llen + n;
9887
        break;
9888
      }
9889
      case OP_FOR_IN_NEXT: {
9890
        /*
9891
         * Data stack layout:
9892
         * ...                                    <-- Bottom of the data stack
9893
         * <iterator_variable_name>   (string)
9894
         * <object_that_is_iterated>  (object)
9895
         * <iterator_foreign_ptr>                 <-- Top of the data stack
9896
         */
9897
        mjs_val_t *iterator = vptr(&mjs->stack, -1);
9898
        mjs_val_t obj = *vptr(&mjs->stack, -2);
9899
        if (mjs_is_object(obj)) {
9900
          mjs_val_t var_name = *vptr(&mjs->stack, -3);
9901
          mjs_val_t key = mjs_next(mjs, obj, iterator);
9902
          if (key != MJS_UNDEFINED) {
9903
            mjs_val_t scope = mjs_find_scope(mjs, var_name);
9904
            mjs_set_v(mjs, scope, var_name, key);
9905
          }
9906
        } else {
9907
          mjs_set_errorf(mjs, MJS_TYPE_ERROR,
9908
                         "can't iterate over non-object value");
9909
        }
9910
        break;
9911
      }
9912
      case OP_RETURN: {
9913
        /*
9914
         * Return address is saved as a global bcode offset, so we need to
9915
         * convert it to the local offset
9916
         */
9917
        size_t off_ret = call_stack_restore_frame(mjs);
9918
        if (off_ret != MJS_BCODE_OFFSET_EXIT) {
9919
          bp = *mjs_bcode_part_get_by_offset(mjs, off_ret);
9920
          code = (const uint8_t *) bp.data.p;
9921
          i = off_ret - bp.start_idx;
9922
          LOG(LL_VERBOSE_DEBUG, ("RETURNING TO %d", (int) off_ret + 1));
9923
        } else {
9924
          goto clean;
9925
        }
9926
        // mjs_dump(mjs, 0, stdout);
9927
        break;
9928
      }
9929
      case OP_ARGS: {
9930
        /*
9931
         * If OP_ARGS follows OP_GET, then last_getprop_obj is set to `this`
9932
         * value; otherwise, last_getprop_obj is irrelevant and we have to
9933
         * reset it to `undefined`
9934
         */
9935
        if (prev_opcode != OP_GET) {
9936
          mjs->vals.last_getprop_obj = MJS_UNDEFINED;
9937
        }
9938
9939
        /*
9940
         * Push last_getprop_obj, which is going to be used as `this`, see
9941
         * OP_CALL
9942
         */
9943
        push_mjs_val(&mjs->arg_stack, mjs->vals.last_getprop_obj);
9944
        /*
9945
         * Push current size of data stack, it's needed to place arguments
9946
         * properly
9947
         */
9948
        push_mjs_val(&mjs->arg_stack,
9949
                     mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->stack)));
9950
        break;
9951
      }
9952
      case OP_CALL: {
9953
        // LOG(LL_INFO, ("BEFORE CALL"));
9954
        // mjs_dump(mjs, 0, stdout);
9955
        int func_pos;
9956
        mjs_val_t *func;
9957
        mjs_val_t retval_stack_idx = vtop(&mjs->arg_stack);
9958
        func_pos = mjs_get_int(mjs, retval_stack_idx) - 1;
9959
        func = vptr(&mjs->stack, func_pos);
9960
9961
        /* Drop data stack size (pushed by OP_ARGS) */
9962
        mjs_pop_val(&mjs->arg_stack);
9963
9964
        if (mjs_is_function(*func)) {
9965
          size_t off_call;
9966
          call_stack_push_frame(mjs, bp.start_idx + i, retval_stack_idx);
9967
9968
          /*
9969
           * Function offset is a global bcode offset, so we need to convert it
9970
           * to the local offset
9971
           */
9972
          off_call = mjs_get_func_addr(*func) - 1;
9973
          bp = *mjs_bcode_part_get_by_offset(mjs, off_call);
9974
          code = (const uint8_t *) bp.data.p;
9975
          i = off_call - bp.start_idx;
9976
9977
          *func = MJS_UNDEFINED;  // Return value
9978
          // LOG(LL_VERBOSE_DEBUG, ("CALLING  %d", i + 1));
9979
        } else if (mjs_is_string(*func) || mjs_is_ffi_sig(*func)) {
9980
          /* Call ffi-ed function */
9981
9982
          call_stack_push_frame(mjs, bp.start_idx + i, retval_stack_idx);
9983
9984
          /* Perform the ffi-ed function call */
9985
          mjs_ffi_call2(mjs);
9986
9987
          call_stack_restore_frame(mjs);
9988
        } else if (mjs_is_foreign(*func)) {
9989
          /* Call cfunction */
9990
9991
          call_stack_push_frame(mjs, bp.start_idx + i, retval_stack_idx);
9992
9993
          /* Perform the cfunction call */
9994
          ((void (*) (struct mjs *)) mjs_get_ptr(mjs, *func))(mjs);
9995
9996
          call_stack_restore_frame(mjs);
9997
        } else {
9998
          mjs_set_errorf(mjs, MJS_TYPE_ERROR, "calling non-callable");
9999
        }
10000
        break;
10001
      }
10002
      case OP_SET_ARG: {
10003
        int llen1, llen2, n,
10004
            arg_no = cs_varint_decode_unsafe(&code[i + 1], &llen1);
10005
        mjs_val_t obj, key, v;
10006
        n = cs_varint_decode_unsafe(&code[i + llen1 + 1], &llen2);
10007
        key = mjs_mk_string(mjs, (char *) code + i + 1 + llen1 + llen2, n, 1);
10008
        obj = vtop(&mjs->scopes);
10009
        v = mjs_arg(mjs, arg_no);
10010
        mjs_set_v(mjs, obj, key, v);
10011
        i += llen1 + llen2 + n;
10012
        break;
10013
      }
10014
      case OP_SETRETVAL: {
10015
2
        if (mjs_stack_size(&mjs->call_stack) < CALL_STACK_FRAME_ITEMS_CNT) {
10016
2
          mjs_set_errorf(mjs, MJS_INTERNAL_ERROR, "cannot return");
10017
        } else {
10018
          size_t retval_pos = mjs_get_int(
10019
              mjs, *vptr(&mjs->call_stack,
10020
                         -1 - CALL_STACK_FRAME_ITEM_RETVAL_STACK_IDX));
10021
          *vptr(&mjs->stack, retval_pos - 1) = mjs_pop(mjs);
10022
        }
10023
        // LOG(LL_INFO, ("AFTER SETRETVAL"));
10024
        // mjs_dump(mjs, 0, stdout);
10025
2
        break;
10026
      }
10027
      case OP_EXPR: {
10028
13
        int op = code[i + 1];
10029
13
        exec_expr(mjs, op);
10030
13
        i++;
10031
13
        break;
10032
      }
10033
      case OP_DROP: {
10034
14
        mjs_pop(mjs);
10035
14
        break;
10036
      }
10037
      case OP_DUP: {
10038
        mjs_push(mjs, vtop(&mjs->stack));
10039
        break;
10040
      }
10041
      case OP_SWAP: {
10042
        mjs_val_t a = mjs_pop(mjs);
10043
        mjs_val_t b = mjs_pop(mjs);
10044
        mjs_push(mjs, a);
10045
        mjs_push(mjs, b);
10046
        break;
10047
      }
10048
      case OP_LOOP: {
10049
        int l1, l2, off = cs_varint_decode_unsafe(&code[i + 1], &l1);
10050
        /* push scope index */
10051
        push_mjs_val(&mjs->loop_addresses,
10052
                     mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->scopes)));
10053
10054
        /* push break offset */
10055
        push_mjs_val(
10056
            &mjs->loop_addresses,
10057
            mjs_mk_number(mjs, (double) (i + 1 /* OP_LOOP */ + l1 + off)));
10058
        off = cs_varint_decode_unsafe(&code[i + 1 + l1], &l2);
10059
10060
        /* push continue offset */
10061
        push_mjs_val(
10062
            &mjs->loop_addresses,
10063
            mjs_mk_number(mjs, (double) (i + 1 /* OP_LOOP*/ + l1 + l2 + off)));
10064
        i += l1 + l2;
10065
        break;
10066
      }
10067
      case OP_CONTINUE: {
10068
1
        if (mjs_stack_size(&mjs->loop_addresses) >= 3) {
10069
          size_t scopes_len = mjs_get_int(mjs, *vptr(&mjs->loop_addresses, -3));
10070
          assert(mjs_stack_size(&mjs->scopes) >= scopes_len);
10071
          mjs->scopes.len = scopes_len * sizeof(mjs_val_t);
10072
10073
          /* jump to "continue" address */
10074
          i = mjs_get_int(mjs, vtop(&mjs->loop_addresses)) - 1;
10075
        } else {
10076
1
          mjs_set_errorf(mjs, MJS_SYNTAX_ERROR, "misplaced 'continue'");
10077
        }
10078
1
      } break;
10079
      case OP_BREAK: {
10080
1
        if (mjs_stack_size(&mjs->loop_addresses) >= 3) {
10081
          size_t scopes_len;
10082
          /* drop "continue" address */
10083
          mjs_pop_val(&mjs->loop_addresses);
10084
10085
          /* pop "break" address and jump to it */
10086
          i = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses)) - 1;
10087
10088
          /* restore scope index */
10089
          scopes_len = mjs_get_int(mjs, mjs_pop_val(&mjs->loop_addresses));
10090
          assert(mjs_stack_size(&mjs->scopes) >= scopes_len);
10091
          mjs->scopes.len = scopes_len * sizeof(mjs_val_t);
10092
10093
          LOG(LL_VERBOSE_DEBUG, ("BREAKING TO %d", (int) i + 1));
10094
        } else {
10095
1
          mjs_set_errorf(mjs, MJS_SYNTAX_ERROR, "misplaced 'break'");
10096
        }
10097
1
      } break;
10098
      case OP_NOP:
10099
        break;
10100
      case OP_EXIT:
10101
16
        i = bp.data.len;
10102
16
        break;
10103
      default:
10104
#if MJS_ENABLE_DEBUG
10105
        mjs_dump(mjs, 1);
10106
#endif
10107
        mjs_set_errorf(mjs, MJS_INTERNAL_ERROR, "Unknown opcode: %d, off %d+%d",
10108
                       (int) opcode, (int) bp.start_idx, (int) i);
10109
        i = bp.data.len;
10110
        break;
10111
    }
10112
248
    if (mjs->error != MJS_OK) {
10113
50
      mjs_gen_stack_trace(mjs, bp.start_idx + i - 1 /* undo the i++ */);
10114
10115
      /* restore stack lenghts */
10116
50
      mjs->stack.len = stack_len;
10117
50
      mjs->call_stack.len = call_stack_len;
10118
50
      mjs->arg_stack.len = arg_stack_len;
10119
50
      mjs->scopes.len = scopes_len;
10120
50
      mjs->loop_addresses.len = loop_addresses_len;
10121
10122
      /* script will evaluate to `undefined` */
10123
50
      mjs_push(mjs, MJS_UNDEFINED);
10124
50
      break;
10125
    }
10126
  }
10127
10128
clean:
10129
  /* Remember result of the evaluation of this bcode part */
10130
66
  mjs_bcode_part_get_by_offset(mjs, start_off)->exec_res = mjs->error;
10131
10132
66
  *res = mjs_pop(mjs);
10133
66
  return mjs->error;
10134
}
10135
10136
78
MJS_PRIVATE mjs_err_t mjs_exec_internal(struct mjs *mjs, const char *path,
10137
                                        const char *src, int generate_jsc,
10138
                                        mjs_val_t *res) {
10139
78
  size_t off = mjs->bcode_len;
10140
78
  mjs_val_t r = MJS_UNDEFINED;
10141
78
  mjs->error = mjs_parse(path, src, mjs);
10142
78
  if (cs_log_threshold >= LL_VERBOSE_DEBUG) mjs_dump(mjs, 1);
10143
78
  if (generate_jsc == -1) generate_jsc = mjs->generate_jsc;
10144
78
  if (mjs->error == MJS_OK) {
10145
#if MJS_GENERATE_JSC && defined(CS_MMAP)
10146
    if (generate_jsc && path != NULL) {
10147
      const char *jsext = ".js";
10148
      int basename_len = (int) strlen(path) - strlen(jsext);
10149
      if (basename_len > 0 && strcmp(path + basename_len, jsext) == 0) {
10150
        /* source file has a .js extension: create a .jsc counterpart */
10151
        int rewrite = 1;
10152
        int read_mmapped = 1;
10153
10154
        /* construct .jsc filename */
10155
        const char *jscext = ".jsc";
10156
        char filename_jsc[basename_len + strlen(jscext) + 1 /* nul-term */];
10157
        memcpy(filename_jsc, path, basename_len);
10158
        strcpy(filename_jsc + basename_len, jscext);
10159
10160
        /* get last bcode part */
10161
        struct mjs_bcode_part *bp =
10162
            mjs_bcode_part_get(mjs, mjs_bcode_parts_cnt(mjs) - 1);
10163
10164
        /*
10165
         * before writing .jsc file, check if it already exists and has the
10166
         * same contents
10167
         *
10168
         * TODO(dfrank): probably store crc32 before the bcode data, and only
10169
         * compare it.
10170
         */
10171
        {
10172
          size_t size;
10173
          char *data = cs_mmap_file(filename_jsc, &size);
10174
          if (data != NULL) {
10175
            if (size == bp->data.len) {
10176
              if (memcmp(data, bp->data.p, size) == 0) {
10177
                /* .jsc file is up to date, so don't rewrite it */
10178
                rewrite = 0;
10179
              }
10180
            }
10181
            munmap(data, size);
10182
          }
10183
        }
10184
10185
        /* try to open .jsc file for writing */
10186
        if (rewrite) {
10187
          FILE *fp = fopen(filename_jsc, "wb");
10188
          if (fp != NULL) {
10189
            /* write last bcode part to .jsc */
10190
            fwrite(bp->data.p, bp->data.len, 1, fp);
10191
            fclose(fp);
10192
          } else {
10193
            LOG(LL_WARN, ("Failed to open %s for writing", filename_jsc));
10194
            read_mmapped = 0;
10195
          }
10196
        }
10197
10198
        if (read_mmapped) {
10199
          /* free RAM buffer with last bcode part */
10200
          free((void *) bp->data.p);
10201
10202
          /* mmap .jsc file and set last bcode part buffer to it */
10203
          bp->data.p = cs_mmap_file(filename_jsc, &bp->data.len);
10204
          bp->in_rom = 1;
10205
        }
10206
      }
10207
    }
10208
#else
10209
    (void) generate_jsc;
10210
#endif
10211
10212
66
    mjs_execute(mjs, off, &r);
10213
  } else {
10214
12
      return mjs->error;
10215
  }
10216
66
  if (res != NULL) *res = r;
10217
66
  return MJS_OK;
10218
//  return mjs->error;
10219
}
10220
10221
78
mjs_err_t mjs_exec(struct mjs *mjs, const char *src, mjs_val_t *res) {
10222
78
  return mjs_exec_internal(mjs, "<stdin>", src, 0 /* generate_jsc */, res);
10223
}
10224
10225
mjs_err_t mjs_exec_file(struct mjs *mjs, const char *path, mjs_val_t *res) {
10226
  mjs_err_t error = MJS_FILE_READ_ERROR;
10227
  mjs_val_t r = MJS_UNDEFINED;
10228
  size_t size;
10229
  char *source_code = cs_read_file(path, &size);
10230
10231
  if (source_code == NULL) {
10232
    error = MJS_FILE_READ_ERROR;
10233
    mjs_prepend_errorf(mjs, error, "failed to read file \"%s\"", path);
10234
    goto clean;
10235
  }
10236
10237
  r = MJS_UNDEFINED;
10238
  error = mjs_exec_internal(mjs, path, source_code, -1, &r);
10239
  free(source_code);
10240
10241
clean:
10242
  if (res != NULL) *res = r;
10243
  return error;
10244
}
10245
10246
mjs_err_t mjs_call(struct mjs *mjs, mjs_val_t *res, mjs_val_t func,
10247
                   mjs_val_t this_val, int nargs, ...) {
10248
  va_list ap;
10249
  int i;
10250
  mjs_err_t ret;
10251
  mjs_val_t *args = calloc(nargs, sizeof(mjs_val_t));
10252
  va_start(ap, nargs);
10253
  for (i = 0; i < nargs; i++) {
10254
    args[i] = va_arg(ap, mjs_val_t);
10255
  }
10256
  va_end(ap);
10257
10258
  ret = mjs_apply(mjs, res, func, this_val, nargs, args);
10259
10260
  free(args);
10261
  return ret;
10262
}
10263
10264
mjs_err_t mjs_apply(struct mjs *mjs, mjs_val_t *res, mjs_val_t func,
10265
                    mjs_val_t this_val, int nargs, mjs_val_t *args) {
10266
  mjs_val_t r, prev_this_val, retval_stack_idx, *resp;
10267
  int i;
10268
10269
  if (!mjs_is_function(func) && !mjs_is_foreign(func) &&
10270
      !mjs_is_ffi_sig(func)) {
10271
    return mjs_set_errorf(mjs, MJS_TYPE_ERROR, "calling non-callable");
10272
  }
10273
10274
  LOG(LL_VERBOSE_DEBUG, ("applying func %d", (int) mjs_get_func_addr(func)));
10275
10276
  prev_this_val = mjs->vals.this_obj;
10277
10278
  /* Push callable which will be later replaced with the return value */
10279
  mjs_push(mjs, func);
10280
  resp = vptr(&mjs->stack, -1);
10281
10282
  /* Remember index by which return value should be written */
10283
  retval_stack_idx = mjs_mk_number(mjs, (double) mjs_stack_size(&mjs->stack));
10284
10285
  // Push all arguments
10286
  for (i = 0; i < nargs; i++) {
10287
    mjs_push(mjs, args[i]);
10288
  }
10289
10290
  /* Push this value to arg_stack, call_stack_push_frame() expects that */
10291
  push_mjs_val(&mjs->arg_stack, this_val);
10292
10293
  /* Push call stack frame, just like OP_CALL does that */
10294
  call_stack_push_frame(mjs, MJS_BCODE_OFFSET_EXIT, retval_stack_idx);
10295
10296
  if (mjs_is_foreign(func)) {
10297
    ((void (*) (struct mjs *)) mjs_get_ptr(mjs, func))(mjs);
10298
    if (res != NULL) *res = *resp;
10299
  } else if (mjs_is_ffi_sig(func)) {
10300
    mjs_ffi_call2(mjs);
10301
    if (res != NULL) *res = *resp;
10302
  } else {
10303
    size_t addr = mjs_get_func_addr(func);
10304
    mjs_execute(mjs, addr, &r);
10305
    if (res != NULL) *res = r;
10306
  }
10307
10308
  /*
10309
   * If there was an error, we need to restore frame and do the cleanup
10310
   * which is otherwise done by OP_RETURN
10311
   */
10312
  if (mjs->error != MJS_OK) {
10313
    call_stack_restore_frame(mjs);
10314
10315
    // Pop cell at which the returned value should've been written
10316
    mjs_pop(mjs);
10317
  }
10318
  mjs->vals.this_obj = prev_this_val;
10319
10320
  return mjs->error;
10321
}
10322
#ifdef MJS_MODULE_LINES
10323
#line 1 "mjs/src/mjs_ffi.c"
10324
#endif
10325
/*
10326
 * Copyright (c) 2017 Cesanta Software Limited
10327
 * All rights reserved
10328
 */
10329
10330
/* Amalgamated: #include "common/mg_str.h" */
10331
10332
/* Amalgamated: #include "mjs/src/ffi/ffi.h" */
10333
/* Amalgamated: #include "mjs/src/mjs_core.h" */
10334
/* Amalgamated: #include "mjs/src/mjs_exec.h" */
10335
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
10336
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
10337
/* Amalgamated: #include "mjs/src/mjs_string.h" */
10338
/* Amalgamated: #include "mjs/src/mjs_util.h" */
10339
10340
/*
10341
 * on linux this is enabled only if __USE_GNU is defined, but we cannot set it
10342
 * because dlfcn could have been included already.
10343
 */
10344
#ifndef RTLD_DEFAULT
10345
#define RTLD_DEFAULT NULL
10346
#endif
10347
10348
static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig);
10349
10350
/*
10351
 * Data of the two related arguments: callback function pointer and the
10352
 * userdata for it
10353
 */
10354
struct cbdata {
10355
  /* JS callback function */
10356
  mjs_val_t func;
10357
  /* JS userdata */
10358
  mjs_val_t userdata;
10359
10360
  /* index of the function pointer param */
10361
  int8_t func_idx;
10362
  /* index of the userdata param */
10363
  int8_t userdata_idx;
10364
};
10365
10366
78
void mjs_set_ffi_resolver(struct mjs *mjs, mjs_ffi_resolver_t *dlsym) {
10367
78
  mjs->dlsym = dlsym;
10368
78
}
10369
10370
static mjs_ffi_ctype_t parse_cval_type(struct mjs *mjs, const char *s,
10371
                                       const char *e) {
10372
  struct mg_str ms = MG_NULL_STR;
10373
  /* Trim leading and trailing whitespace */
10374
  while (s < e && isspace((int) *s)) s++;
10375
  while (e > s && isspace((int) e[-1])) e--;
10376
  ms.p = s;
10377
  ms.len = e - s;
10378
  if (mg_vcmp(&ms, "void") == 0) {
10379
    return MJS_FFI_CTYPE_NONE;
10380
  } else if (mg_vcmp(&ms, "userdata") == 0) {
10381
    return MJS_FFI_CTYPE_USERDATA;
10382
  } else if (mg_vcmp(&ms, "int") == 0) {
10383
    return MJS_FFI_CTYPE_INT;
10384
  } else if (mg_vcmp(&ms, "bool") == 0) {
10385
    return MJS_FFI_CTYPE_BOOL;
10386
  } else if (mg_vcmp(&ms, "double") == 0) {
10387
    return MJS_FFI_CTYPE_DOUBLE;
10388
  } else if (mg_vcmp(&ms, "float") == 0) {
10389
    return MJS_FFI_CTYPE_FLOAT;
10390
  } else if (mg_vcmp(&ms, "char*") == 0 || mg_vcmp(&ms, "char *") == 0) {
10391
    return MJS_FFI_CTYPE_CHAR_PTR;
10392
  } else if (mg_vcmp(&ms, "void*") == 0 || mg_vcmp(&ms, "void *") == 0) {
10393
    return MJS_FFI_CTYPE_VOID_PTR;
10394
  } else if (mg_vcmp(&ms, "struct mg_str") == 0) {
10395
    return MJS_FFI_CTYPE_STRUCT_MG_STR;
10396
  } else if (mg_vcmp(&ms, "struct mg_str *") == 0 ||
10397
             mg_vcmp(&ms, "struct mg_str*") == 0) {
10398
    return MJS_FFI_CTYPE_STRUCT_MG_STR_PTR;
10399
  } else {
10400
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "failed to parse val type \"%.*s\"",
10401
                       (int) ms.len, ms.p);
10402
    return MJS_FFI_CTYPE_INVALID;
10403
  }
10404
}
10405
10406
static const char *find_paren(const char *s, const char *e) {
10407
  for (; s < e; s++) {
10408
    if (*s == '(') return s;
10409
  }
10410
  return NULL;
10411
}
10412
10413
static const char *find_closing_paren(const char *s, const char *e) {
10414
  int nesting = 1;
10415
  while (s < e) {
10416
    if (*s == '(') {
10417
      nesting++;
10418
    } else if (*s == ')') {
10419
      if (--nesting == 0) break;
10420
    }
10421
    s++;
10422
  }
10423
  return (s < e ? s : NULL);
10424
}
10425
10426
MJS_PRIVATE mjs_err_t mjs_parse_ffi_signature(struct mjs *mjs, const char *s,
10427
                                              int sig_len, mjs_ffi_sig_t *sig,
10428
                                              enum ffi_sig_type sig_type) {
10429
  mjs_err_t ret = MJS_OK;
10430
  int vtidx = 0;
10431
  const char *cur, *e, *tmp_e, *tmp;
10432
  struct mg_str rt = MG_NULL_STR, fn = MG_NULL_STR, args = MG_NULL_STR;
10433
  mjs_ffi_ctype_t val_type = MJS_FFI_CTYPE_INVALID;
10434
  if (sig_len == ~0) {
10435
    sig_len = strlen(s);
10436
  }
10437
  e = s + sig_len;
10438
10439
  mjs_ffi_sig_init(sig);
10440
10441
  /* Skip leading spaces */
10442
  for (cur = s; cur < e && isspace((int) *cur); cur++)
10443
    ;
10444
10445
  /* FInd the first set of parens */
10446
  tmp_e = find_paren(cur, e);
10447
  if (tmp_e == NULL || tmp_e - s < 2) {
10448
    ret = MJS_TYPE_ERROR;
10449
    mjs_prepend_errorf(mjs, ret, "1");
10450
    goto clean;
10451
  }
10452
  tmp = find_closing_paren(tmp_e + 1, e);
10453
  if (tmp == NULL) {
10454
    ret = MJS_TYPE_ERROR;
10455
    mjs_prepend_errorf(mjs, ret, "2");
10456
    goto clean;
10457
  }
10458
10459
  /* Now see if we have a second set of parens */
10460
  args.p = find_paren(tmp + 1, e);
10461
  if (args.p == NULL) {
10462
    /* We don't - it's a regular function signature */
10463
    fn.p = tmp_e - 1;
10464
    while (fn.p > cur && isspace((int) *fn.p)) fn.p--;
10465
    while (fn.p > cur && (isalnum((int) *fn.p) || *fn.p == '_')) {
10466
      fn.p--;
10467
      fn.len++;
10468
    }
10469
    fn.p++;
10470
    rt.p = cur;
10471
    rt.len = fn.p - rt.p;
10472
    /* Stuff inside parens is args */
10473
    args.p = tmp_e + 1;
10474
    args.len = tmp - args.p;
10475
  } else {
10476
    /* We do - it's a function pointer, like void (*foo)(...).
10477
     * Stuff inside the first pair of parens is the function name */
10478
    fn.p = tmp + 1;
10479
    fn.len = args.p - tmp;
10480
    rt.p = cur;
10481
    rt.len = tmp_e - rt.p;
10482
    args.p++;
10483
    tmp = find_closing_paren(args.p, e);
10484
    if (tmp == NULL) {
10485
      ret = MJS_TYPE_ERROR;
10486
      mjs_prepend_errorf(mjs, ret, "3");
10487
      goto clean;
10488
    }
10489
    args.len = tmp - args.p;
10490
    /*
10491
     * We ignore the name and leave sig->fn NULL here, but it will later be
10492
     * set to the appropriate callback implementation.
10493
     */
10494
    sig->is_callback = 1;
10495
  }
10496
10497
  val_type = parse_cval_type(mjs, rt.p, rt.p + rt.len);
10498
  if (val_type == MJS_FFI_CTYPE_INVALID) {
10499
    ret = mjs->error;
10500
    goto clean;
10501
  }
10502
  mjs_ffi_sig_set_val_type(sig, vtidx++, val_type);
10503
10504
  /* Parse function name {{{ */
10505
  if (!sig->is_callback) {
10506
    char buf[100];
10507
    if (mjs->dlsym == NULL) {
10508
      ret = MJS_TYPE_ERROR;
10509
      mjs_prepend_errorf(mjs, ret,
10510
                         "resolver is not set, call mjs_set_ffi_resolver");
10511
      goto clean;
10512
    }
10513
10514
    snprintf(buf, sizeof(buf), "%.*s", (int) fn.len, fn.p);
10515
    sig->fn = (ffi_fn_t *) mjs->dlsym(RTLD_DEFAULT, buf);
10516
    if (sig->fn == NULL) {
10517
      ret = MJS_TYPE_ERROR;
10518
      mjs_prepend_errorf(mjs, ret, "dlsym('%s') failed", buf);
10519
      goto clean;
10520
    }
10521
  } else {
10522
    tmp_e = strchr(tmp_e, ')');
10523
    if (tmp_e == NULL) {
10524
      ret = MJS_TYPE_ERROR;
10525
      goto clean;
10526
    }
10527
  }
10528
10529
  /* Advance cur to the beginning of the arg list */
10530
  cur = tmp_e = args.p;
10531
10532
  /* Parse all args {{{ */
10533
  while (tmp_e - args.p < (ptrdiff_t) args.len) {
10534
    int level = 0; /* nested parens level */
10535
    int is_fp = 0; /* set to 1 is current arg is a callback function ptr */
10536
    tmp_e = cur;
10537
10538
    /* Advance tmp_e until the next arg separator */
10539
    while (*tmp_e && (level > 0 || (*tmp_e != ',' && *tmp_e != ')'))) {
10540
      switch (*tmp_e) {
10541
        case '(':
10542
          level++;
10543
          /*
10544
           * only function pointer params can have parens, so, set the flag
10545
           * that it's going to be a function pointer
10546
           */
10547
          is_fp = 1;
10548
          break;
10549
        case ')':
10550
          level--;
10551
          break;
10552
      }
10553
      tmp_e++;
10554
    }
10555
10556
    if (tmp_e == cur) break;
10557
10558
    /* Parse current arg */
10559
    if (is_fp) {
10560
      /* Current argument is a callback function pointer */
10561
      if (sig->cb_sig != NULL) {
10562
        /*
10563
         * We already have parsed some callback argument. Currently we don't
10564
         * support more than one callback argument, so, return error
10565
         * TODO(dfrank): probably improve
10566
         */
10567
        ret = MJS_TYPE_ERROR;
10568
        mjs_prepend_errorf(mjs, ret, "only one callback is allowed");
10569
        goto clean;
10570
      }
10571
10572
      sig->cb_sig = calloc(sizeof(*sig->cb_sig), 1);
10573
      ret = mjs_parse_ffi_signature(mjs, cur, tmp_e - cur, sig->cb_sig,
10574
                                    FFI_SIG_CALLBACK);
10575
      if (ret != MJS_OK) {
10576
        mjs_ffi_sig_free(sig->cb_sig);
10577
        free(sig->cb_sig);
10578
        sig->cb_sig = NULL;
10579
        goto clean;
10580
      }
10581
      val_type = MJS_FFI_CTYPE_CALLBACK;
10582
    } else {
10583
      /* Some non-function argument */
10584
      val_type = parse_cval_type(mjs, cur, tmp_e);
10585
      if (val_type == MJS_FFI_CTYPE_INVALID) {
10586
        /* parse_cval_type() has already set error message */
10587
        ret = MJS_TYPE_ERROR;
10588
        goto clean;
10589
      }
10590
    }
10591
10592
    if (!mjs_ffi_sig_set_val_type(sig, vtidx++, val_type)) {
10593
      ret = MJS_TYPE_ERROR;
10594
      mjs_prepend_errorf(mjs, ret, "too many callback args");
10595
      goto clean;
10596
    }
10597
10598
    if (*tmp_e == ',') {
10599
      /* Advance cur to the next argument */
10600
      cur = tmp_e + 1;
10601
      while (*cur == ' ') cur++;
10602
    } else {
10603
      /* No more arguments */
10604
      break;
10605
    }
10606
  }
10607
  /* }}} */
10608
10609
  /* Analyze the results and see if they are obviously wrong */
10610
  mjs_ffi_sig_validate(mjs, sig, sig_type);
10611
  if (!sig->is_valid) {
10612
    ret = MJS_TYPE_ERROR;
10613
    goto clean;
10614
  }
10615
10616
  /* If the signature represents a callback, find the suitable implementation */
10617
  if (sig->is_callback) {
10618
    sig->fn = get_cb_impl_by_signature(sig);
10619
    if (sig->fn == NULL) {
10620
      ret = MJS_TYPE_ERROR;
10621
      mjs_prepend_errorf(mjs, ret,
10622
                         "the callback signature is valid, but there's "
10623
                         "no existing callback implementation for it");
10624
      goto clean;
10625
    }
10626
  }
10627
10628
clean:
10629
  if (ret != MJS_OK) {
10630
    mjs_prepend_errorf(mjs, ret, "bad ffi signature: \"%.*s\"", sig_len, s);
10631
    sig->is_valid = 0;
10632
  }
10633
  return ret;
10634
}
10635
10636
/* C callbacks implementation {{{ */
10637
10638
/* An argument or a return value for C callback impl */
10639
union ffi_cb_data_val {
10640
  void *p;
10641
  uintptr_t w;
10642
  double d;
10643
  float f;
10644
};
10645
10646
struct ffi_cb_data {
10647
  union ffi_cb_data_val args[MJS_CB_ARGS_MAX_CNT];
10648
};
10649
10650
static union ffi_cb_data_val ffi_cb_impl_generic(void *param,
10651
                                                 struct ffi_cb_data *data) {
10652
  struct mjs_ffi_cb_args *cbargs = (struct mjs_ffi_cb_args *) param;
10653
  mjs_val_t *args, res = MJS_UNDEFINED;
10654
  union ffi_cb_data_val ret;
10655
  int i;
10656
  struct mjs *mjs = cbargs->mjs;
10657
  mjs_ffi_ctype_t return_ctype = MJS_FFI_CTYPE_NONE;
10658
  mjs_err_t err;
10659
10660
  memset(&ret, 0, sizeof(ret));
10661
  mjs_own(mjs, &res);
10662
10663
  /* There must be at least one argument: a userdata */
10664
  assert(cbargs->sig.args_cnt > 0);
10665
10666
  /* Create JS arguments */
10667
  args = calloc(1, sizeof(mjs_val_t) * cbargs->sig.args_cnt);
10668
  for (i = 0; i < cbargs->sig.args_cnt; i++) {
10669
    mjs_ffi_ctype_t val_type =
10670
        cbargs->sig.val_types[i + 1 /* first val_type is return value type */];
10671
    switch (val_type) {
10672
      case MJS_FFI_CTYPE_USERDATA:
10673
        args[i] = cbargs->userdata;
10674
        break;
10675
      case MJS_FFI_CTYPE_INT:
10676
        args[i] = mjs_mk_number(mjs, (double) data->args[i].w);
10677
        break;
10678
      case MJS_FFI_CTYPE_BOOL:
10679
        args[i] = mjs_mk_boolean(mjs, !!data->args[i].w);
10680
        break;
10681
      case MJS_FFI_CTYPE_CHAR_PTR: {
10682
        const char *s = (char *) data->args[i].w;
10683
        if (s == NULL) s = "";
10684
        args[i] = mjs_mk_string(mjs, s, ~0, 1);
10685
        break;
10686
      }
10687
      case MJS_FFI_CTYPE_VOID_PTR:
10688
        args[i] = mjs_mk_foreign(mjs, (void *) data->args[i].w);
10689
        break;
10690
      case MJS_FFI_CTYPE_DOUBLE:
10691
        args[i] = mjs_mk_number(mjs, data->args[i].d);
10692
        break;
10693
      case MJS_FFI_CTYPE_FLOAT:
10694
        args[i] = mjs_mk_number(mjs, data->args[i].f);
10695
        break;
10696
      case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: {
10697
        struct mg_str *s = (struct mg_str *) (void *) data->args[i].w;
10698
        args[i] = mjs_mk_string(mjs, s->p, s->len, 1);
10699
        break;
10700
      }
10701
      default:
10702
        /* should never be here */
10703
        LOG(LL_ERROR, ("unexpected val type for arg #%d: %d\n", i, val_type));
10704
        abort();
10705
    }
10706
  }
10707
10708
  /*
10709
   * save return ctype outside of `cbargs` before calling the callback, because
10710
   * callback might call `ffi_cb_free()`, which will effectively invalidate
10711
   * `cbargs`
10712
   */
10713
  return_ctype = cbargs->sig.val_types[0];
10714
10715
  /* Call JS function */
10716
  LOG(LL_VERBOSE_DEBUG, ("calling JS callback void-void %d from C",
10717
                         mjs_get_int(mjs, cbargs->func)));
10718
  err = mjs_apply(mjs, &res, cbargs->func, MJS_UNDEFINED, cbargs->sig.args_cnt,
10719
                  args);
10720
  /*
10721
   * cbargs might be invalidated by the callback (if it called ffi_cb_free), so
10722
   * null it out
10723
   */
10724
  cbargs = NULL;
10725
  if (err != MJS_OK) {
10726
    /*
10727
     * There's not much we can do about the error here; let's at least print it
10728
     */
10729
    mjs_print_error(mjs, stderr, "MJS callback error",
10730
                    1 /* print_stack_trace */);
10731
10732
    goto clean;
10733
  }
10734
10735
  /* Get return value, if needed */
10736
  switch (return_ctype) {
10737
    case MJS_FFI_CTYPE_NONE:
10738
      /* do nothing */
10739
      break;
10740
    case MJS_FFI_CTYPE_INT:
10741
      ret.w = mjs_get_int(mjs, res);
10742
      break;
10743
    case MJS_FFI_CTYPE_BOOL:
10744
      ret.w = mjs_get_bool(mjs, res);
10745
      break;
10746
    case MJS_FFI_CTYPE_VOID_PTR:
10747
      ret.p = mjs_get_ptr(mjs, res);
10748
      break;
10749
    case MJS_FFI_CTYPE_DOUBLE:
10750
      ret.d = mjs_get_double(mjs, res);
10751
      break;
10752
    case MJS_FFI_CTYPE_FLOAT:
10753
      ret.f = (float) mjs_get_double(mjs, res);
10754
      break;
10755
    default:
10756
      /* should never be here */
10757
      LOG(LL_ERROR, ("unexpected return val type %d\n", return_ctype));
10758
      abort();
10759
  }
10760
10761
clean:
10762
  free(args);
10763
  mjs_disown(mjs, &res);
10764
  return ret;
10765
}
10766
10767
static void ffi_init_cb_data_wwww(struct ffi_cb_data *data, uintptr_t w0,
10768
                                  uintptr_t w1, uintptr_t w2, uintptr_t w3,
10769
                                  uintptr_t w4, uintptr_t w5) {
10770
  memset(data, 0, sizeof(*data));
10771
  data->args[0].w = w0;
10772
  data->args[1].w = w1;
10773
  data->args[2].w = w2;
10774
  data->args[3].w = w3;
10775
  data->args[4].w = w4;
10776
  data->args[5].w = w5;
10777
}
10778
10779
static uintptr_t ffi_cb_impl_wpwwwww(uintptr_t w0, uintptr_t w1, uintptr_t w2,
10780
                                     uintptr_t w3, uintptr_t w4, uintptr_t w5) {
10781
  struct ffi_cb_data data;
10782
  ffi_init_cb_data_wwww(&data, w0, w1, w2, w3, w4, w5);
10783
  return ffi_cb_impl_generic((void *) w0, &data).w;
10784
}
10785
10786
static uintptr_t ffi_cb_impl_wwpwwww(uintptr_t w0, uintptr_t w1, uintptr_t w2,
10787
                                     uintptr_t w3, uintptr_t w4, uintptr_t w5) {
10788
  struct ffi_cb_data data;
10789
  ffi_init_cb_data_wwww(&data, w0, w1, w2, w3, w4, w5);
10790
  return ffi_cb_impl_generic((void *) w1, &data).w;
10791
}
10792
10793
static uintptr_t ffi_cb_impl_wwwpwww(uintptr_t w0, uintptr_t w1, uintptr_t w2,
10794
                                     uintptr_t w3, uintptr_t w4, uintptr_t w5) {
10795
  struct ffi_cb_data data;
10796
  ffi_init_cb_data_wwww(&data, w0, w1, w2, w3, w4, w5);
10797
  return ffi_cb_impl_generic((void *) w2, &data).w;
10798
}
10799
10800
static uintptr_t ffi_cb_impl_wwwwpww(uintptr_t w0, uintptr_t w1, uintptr_t w2,
10801
                                     uintptr_t w3, uintptr_t w4, uintptr_t w5) {
10802
  struct ffi_cb_data data;
10803
  ffi_init_cb_data_wwww(&data, w0, w1, w2, w3, w4, w5);
10804
  return ffi_cb_impl_generic((void *) w3, &data).w;
10805
}
10806
10807
static uintptr_t ffi_cb_impl_wwwwwpw(uintptr_t w0, uintptr_t w1, uintptr_t w2,
10808
                                     uintptr_t w3, uintptr_t w4, uintptr_t w5) {
10809
  struct ffi_cb_data data;
10810
  ffi_init_cb_data_wwww(&data, w0, w1, w2, w3, w4, w5);
10811
  return ffi_cb_impl_generic((void *) w4, &data).w;
10812
}
10813
10814
static uintptr_t ffi_cb_impl_wwwwwwp(uintptr_t w0, uintptr_t w1, uintptr_t w2,
10815
                                     uintptr_t w3, uintptr_t w4, uintptr_t w5) {
10816
  struct ffi_cb_data data;
10817
  ffi_init_cb_data_wwww(&data, w0, w1, w2, w3, w4, w5);
10818
  return ffi_cb_impl_generic((void *) w5, &data).w;
10819
}
10820
10821
static uintptr_t ffi_cb_impl_wpd(uintptr_t w0, double d1) {
10822
  struct ffi_cb_data data;
10823
10824
  memset(&data, 0, sizeof(data));
10825
  data.args[0].w = w0;
10826
  data.args[1].d = d1;
10827
10828
  return ffi_cb_impl_generic((void *) w0, &data).w;
10829
}
10830
10831
static uintptr_t ffi_cb_impl_wdp(double d0, uintptr_t w1) {
10832
  struct ffi_cb_data data;
10833
10834
  memset(&data, 0, sizeof(data));
10835
  data.args[0].d = d0;
10836
  data.args[1].w = w1;
10837
10838
  return ffi_cb_impl_generic((void *) w1, &data).w;
10839
}
10840
/* }}} */
10841
10842
static struct mjs_ffi_cb_args **ffi_get_matching(struct mjs_ffi_cb_args **plist,
10843
                                                 mjs_val_t func,
10844
                                                 mjs_val_t userdata) {
10845
  for (; *plist != NULL; plist = &((*plist)->next)) {
10846
    if ((*plist)->func == func && (*plist)->userdata == userdata) {
10847
      break;
10848
    }
10849
  }
10850
  return plist;
10851
}
10852
10853
static ffi_fn_t *get_cb_impl_by_signature(const mjs_ffi_sig_t *sig) {
10854
  if (sig->is_valid) {
10855
    int i;
10856
    int double_cnt = 0;
10857
    int float_cnt = 0;
10858
    int userdata_idx = 0 /* not a valid value: index 0 means return value */;
10859
10860
    for (i = 1 /*0th item is a return value*/; i < MJS_CB_SIGNATURE_MAX_SIZE;
10861
         i++) {
10862
      mjs_ffi_ctype_t type = sig->val_types[i];
10863
      switch (type) {
10864
        case MJS_FFI_CTYPE_DOUBLE:
10865
          double_cnt++;
10866
          break;
10867
        case MJS_FFI_CTYPE_FLOAT:
10868
          float_cnt++;
10869
          break;
10870
        case MJS_FFI_CTYPE_USERDATA:
10871
          assert(userdata_idx == 0); /* Otherwise is_valid should be 0 */
10872
          userdata_idx = i;
10873
          break;
10874
        default:
10875
          break;
10876
      }
10877
    }
10878
10879
    if (float_cnt > 0) {
10880
      /* TODO(dfrank): add support for floats in callbacks */
10881
      return NULL;
10882
    }
10883
10884
    assert(userdata_idx > 0); /* Otherwise is_valid should be 0 */
10885
10886
    if (sig->args_cnt <= MJS_CB_ARGS_MAX_CNT) {
10887
      if (mjs_ffi_is_regular_word_or_void(sig->val_types[0])) {
10888
        /* Return type is a word or void */
10889
        switch (double_cnt) {
10890
          case 0:
10891
            /* No double arguments */
10892
            switch (userdata_idx) {
10893
              case 1:
10894
                return (ffi_fn_t *) ffi_cb_impl_wpwwwww;
10895
              case 2:
10896
                return (ffi_fn_t *) ffi_cb_impl_wwpwwww;
10897
              case 3:
10898
                return (ffi_fn_t *) ffi_cb_impl_wwwpwww;
10899
              case 4:
10900
                return (ffi_fn_t *) ffi_cb_impl_wwwwpww;
10901
              case 5:
10902
                return (ffi_fn_t *) ffi_cb_impl_wwwwwpw;
10903
              case 6:
10904
                return (ffi_fn_t *) ffi_cb_impl_wwwwwwp;
10905
              default:
10906
                /* should never be here */
10907
                abort();
10908
            }
10909
            break;
10910
          case 1:
10911
            /* 1 double argument */
10912
            switch (userdata_idx) {
10913
              case 1:
10914
                return (ffi_fn_t *) ffi_cb_impl_wpd;
10915
              case 2:
10916
                return (ffi_fn_t *) ffi_cb_impl_wdp;
10917
            }
10918
            break;
10919
        }
10920
      }
10921
    } else {
10922
      /* Too many arguments for the built-in callback impls */
10923
      /* TODO(dfrank): add support for custom app-dependent resolver */
10924
    }
10925
  }
10926
10927
  return NULL;
10928
}
10929
10930
MJS_PRIVATE mjs_val_t mjs_ffi_sig_to_value(struct mjs_ffi_sig *psig) {
10931
  if (psig == NULL) {
10932
    return MJS_NULL;
10933
  } else {
10934
    return mjs_legit_pointer_to_value(psig) | MJS_TAG_FUNCTION_FFI;
10935
  }
10936
}
10937
10938
2682
MJS_PRIVATE int mjs_is_ffi_sig(mjs_val_t v) {
10939
2682
  return (v & MJS_TAG_MASK) == MJS_TAG_FUNCTION_FFI;
10940
}
10941
10942
MJS_PRIVATE struct mjs_ffi_sig *mjs_get_ffi_sig_struct(mjs_val_t v) {
10943
  struct mjs_ffi_sig *ret = NULL;
10944
  assert(mjs_is_ffi_sig(v));
10945
  ret = (struct mjs_ffi_sig *) get_ptr(v);
10946
  return ret;
10947
}
10948
10949
MJS_PRIVATE mjs_val_t mjs_mk_ffi_sig(struct mjs *mjs) {
10950
  struct mjs_ffi_sig *psig = new_ffi_sig(mjs);
10951
  mjs_ffi_sig_init(psig);
10952
  return mjs_ffi_sig_to_value(psig);
10953
}
10954
10955
MJS_PRIVATE void mjs_ffi_sig_destructor(struct mjs *mjs, void *psig) {
10956
  mjs_ffi_sig_free((mjs_ffi_sig_t *) psig);
10957
  (void) mjs;
10958
}
10959
10960
MJS_PRIVATE mjs_err_t mjs_ffi_call(struct mjs *mjs) {
10961
  mjs_err_t e = MJS_OK;
10962
  const char *sig_str = NULL;
10963
  mjs_val_t sig_str_v = mjs_arg(mjs, 0);
10964
  mjs_val_t ret_v = MJS_UNDEFINED;
10965
  struct mjs_ffi_sig *psig = mjs_get_ffi_sig_struct(mjs_mk_ffi_sig(mjs));
10966
  size_t sig_str_len;
10967
10968
  sig_str = mjs_get_string(mjs, &sig_str_v, &sig_str_len);
10969
  e = mjs_parse_ffi_signature(mjs, sig_str, sig_str_len, psig, FFI_SIG_FUNC);
10970
  if (e != MJS_OK) goto clean;
10971
  ret_v = mjs_ffi_sig_to_value(psig);
10972
10973
clean:
10974
  mjs_return(mjs, ret_v);
10975
  return e;
10976
}
10977
10978
MJS_PRIVATE mjs_err_t mjs_ffi_call2(struct mjs *mjs) {
10979
  mjs_err_t ret = MJS_OK;
10980
  mjs_ffi_sig_t *psig = NULL;
10981
  mjs_ffi_ctype_t rtype;
10982
  mjs_val_t sig_v = *vptr(&mjs->stack, mjs_getretvalpos(mjs));
10983
10984
  int i, nargs;
10985
  struct ffi_arg res;
10986
  struct ffi_arg args[FFI_MAX_ARGS_CNT];
10987
  struct cbdata cbdata;
10988
10989
  /* TODO(dfrank): support multiple callbacks */
10990
  mjs_val_t resv = mjs_mk_undefined();
10991
10992
  /*
10993
   * String arguments, needed to support short strings which are packed into
10994
   * mjs_val_t itself
10995
   */
10996
  mjs_val_t argvs[FFI_MAX_ARGS_CNT];
10997
  struct mg_str argvmgstr[FFI_MAX_ARGS_CNT];
10998
10999
  if (mjs_is_ffi_sig(sig_v)) {
11000
    psig = mjs_get_ffi_sig_struct(sig_v);
11001
  } else {
11002
    ret = MJS_TYPE_ERROR;
11003
    mjs_prepend_errorf(mjs, ret, "non-ffi-callable value");
11004
    goto clean;
11005
  }
11006
11007
  memset(&cbdata, 0, sizeof(cbdata));
11008
  cbdata.func_idx = -1;
11009
  cbdata.userdata_idx = -1;
11010
11011
  rtype = psig->val_types[0];
11012
11013
  switch (rtype) {
11014
    case MJS_FFI_CTYPE_DOUBLE:
11015
      res.ctype = FFI_CTYPE_DOUBLE;
11016
      break;
11017
    case MJS_FFI_CTYPE_FLOAT:
11018
      res.ctype = FFI_CTYPE_FLOAT;
11019
      break;
11020
    case MJS_FFI_CTYPE_BOOL:
11021
      res.ctype = FFI_CTYPE_BOOL;
11022
      break;
11023
    case MJS_FFI_CTYPE_USERDATA:
11024
    case MJS_FFI_CTYPE_INT:
11025
    case MJS_FFI_CTYPE_CHAR_PTR:
11026
    case MJS_FFI_CTYPE_VOID_PTR:
11027
    case MJS_FFI_CTYPE_NONE:
11028
      res.ctype = FFI_CTYPE_WORD;
11029
      break;
11030
11031
    case MJS_FFI_CTYPE_INVALID:
11032
      ret = MJS_TYPE_ERROR;
11033
      mjs_prepend_errorf(mjs, ret, "wrong ffi return type");
11034
      goto clean;
11035
  }
11036
  res.v.i = 0;
11037
11038
  nargs =
11039
      mjs_stack_size(&mjs->stack) - mjs_get_int(mjs, vtop(&mjs->call_stack));
11040
11041
  if (nargs != psig->args_cnt) {
11042
    ret = MJS_TYPE_ERROR;
11043
    mjs_prepend_errorf(mjs, ret, "got %d actuals, but function takes %d args",
11044
                       nargs, psig->args_cnt);
11045
    goto clean;
11046
  }
11047
11048
  for (i = 0; i < nargs; i++) {
11049
    mjs_val_t arg = mjs_arg(mjs, i);
11050
11051
    switch (psig->val_types[1 /* retval type */ + i]) {
11052
      case MJS_FFI_CTYPE_NONE:
11053
        /*
11054
         * Void argument: in any case, it's an error, because if C function
11055
         * takes no arguments, then the FFI-ed JS function should be called
11056
         * without any arguments, and thus we'll not face "void" here.
11057
         */
11058
        ret = MJS_TYPE_ERROR;
11059
        if (i == 0) {
11060
          /* FFI signature is correct, but invocation is wrong */
11061
          mjs_prepend_errorf(mjs, ret, "ffi-ed function takes no arguments");
11062
        } else {
11063
          /*
11064
           * FFI signature is wrong: we can't have "void" as a non-first
11065
           * "argument"
11066
           */
11067
          mjs_prepend_errorf(mjs, ret, "bad ffi arg #%d type: \"void\"", i);
11068
        }
11069
11070
        goto clean;
11071
      case MJS_FFI_CTYPE_USERDATA:
11072
        /* Userdata for the callback */
11073
        if (cbdata.userdata_idx != -1) {
11074
          ret = MJS_TYPE_ERROR;
11075
          mjs_prepend_errorf(mjs, ret, "two or more userdata args: #%d and %d",
11076
                             cbdata.userdata_idx, i);
11077
11078
          goto clean;
11079
        }
11080
        cbdata.userdata = arg;
11081
        cbdata.userdata_idx = i;
11082
        break;
11083
      case MJS_FFI_CTYPE_INT: {
11084
        int intval = 0;
11085
        if (mjs_is_number(arg)) {
11086
          intval = mjs_get_int(mjs, arg);
11087
        } else if (mjs_is_boolean(arg)) {
11088
          intval = mjs_get_bool(mjs, arg);
11089
        } else {
11090
          ret = MJS_TYPE_ERROR;
11091
          mjs_prepend_errorf(
11092
              mjs, ret, "actual arg #%d is not an int (the type idx is: %s)", i,
11093
              mjs_typeof(arg));
11094
        }
11095
        ffi_set_word(&args[i], intval);
11096
      } break;
11097
      case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: {
11098
        if (!mjs_is_string(arg)) {
11099
          ret = MJS_TYPE_ERROR;
11100
          mjs_prepend_errorf(
11101
              mjs, ret, "actual arg #%d is not a string (the type idx is: %s)",
11102
              i, mjs_typeof(arg));
11103
          goto clean;
11104
        }
11105
        argvs[i] = arg;
11106
        argvmgstr[i].p = mjs_get_string(mjs, &argvs[i], &argvmgstr[i].len);
11107
        /*
11108
         * String argument should be saved separately in order to support
11109
         * short strings (which are packed into mjs_val_t itself)
11110
         */
11111
        ffi_set_ptr(&args[i], (void *) &argvmgstr[i]);
11112
        break;
11113
      }
11114
      case MJS_FFI_CTYPE_BOOL: {
11115
        int intval = 0;
11116
        if (mjs_is_number(arg)) {
11117
          intval = !!mjs_get_int(mjs, arg);
11118
        } else if (mjs_is_boolean(arg)) {
11119
          intval = mjs_get_bool(mjs, arg);
11120
        } else {
11121
          ret = MJS_TYPE_ERROR;
11122
          mjs_prepend_errorf(
11123
              mjs, ret, "actual arg #%d is not a bool (the type idx is: %s)", i,
11124
              mjs_typeof(arg));
11125
        }
11126
        ffi_set_word(&args[i], intval);
11127
      } break;
11128
      case MJS_FFI_CTYPE_DOUBLE:
11129
        ffi_set_double(&args[i], mjs_get_double(mjs, arg));
11130
        break;
11131
      case MJS_FFI_CTYPE_FLOAT:
11132
        ffi_set_float(&args[i], (float) mjs_get_double(mjs, arg));
11133
        break;
11134
      case MJS_FFI_CTYPE_CHAR_PTR: {
11135
        size_t s;
11136
        if (mjs_is_string(arg)) {
11137
          /*
11138
           * String argument should be saved separately in order to support
11139
           * short strings (which are packed into mjs_val_t itself)
11140
           */
11141
          argvs[i] = arg;
11142
          ffi_set_ptr(&args[i], (void *) mjs_get_string(mjs, &argvs[i], &s));
11143
        } else if (mjs_is_null(arg)) {
11144
          ffi_set_ptr(&args[i], NULL);
11145
        } else {
11146
          ret = MJS_TYPE_ERROR;
11147
          mjs_prepend_errorf(
11148
              mjs, ret, "actual arg #%d is not a string (the type idx is: %s)",
11149
              i, mjs_typeof(arg));
11150
          goto clean;
11151
        }
11152
      } break;
11153
      case MJS_FFI_CTYPE_VOID_PTR:
11154
        if (mjs_is_string(arg)) {
11155
          size_t n;
11156
          /*
11157
           * String argument should be saved separately in order to support
11158
           * short strings (which are packed into mjs_val_t itself)
11159
           */
11160
          argvs[i] = arg;
11161
          ffi_set_ptr(&args[i], (void *) mjs_get_string(mjs, &argvs[i], &n));
11162
        } else if (mjs_is_foreign(arg)) {
11163
          ffi_set_ptr(&args[i], (void *) mjs_get_ptr(mjs, arg));
11164
        } else if (mjs_is_null(arg)) {
11165
          ffi_set_ptr(&args[i], NULL);
11166
        } else {
11167
          ret = MJS_TYPE_ERROR;
11168
          mjs_prepend_errorf(mjs, ret, "actual arg #%d is not a ptr", i);
11169
          goto clean;
11170
        }
11171
        break;
11172
      case MJS_FFI_CTYPE_CALLBACK:
11173
        if (mjs_is_function(arg) || mjs_is_foreign(arg) ||
11174
            mjs_is_ffi_sig(arg)) {
11175
          /*
11176
           * Current argument is a callback function pointer: remember the given
11177
           * JS function and the argument index
11178
           */
11179
          cbdata.func = arg;
11180
          cbdata.func_idx = i;
11181
        } else {
11182
          ret = MJS_TYPE_ERROR;
11183
          mjs_prepend_errorf(mjs, ret,
11184
                             "actual arg #%d is not a function, but %s", i,
11185
                             mjs_stringify_type((enum mjs_type) arg));
11186
          goto clean;
11187
        }
11188
        break;
11189
      case MJS_FFI_CTYPE_INVALID:
11190
        /* parse_cval_type() has already set a more detailed error */
11191
        ret = MJS_TYPE_ERROR;
11192
        mjs_prepend_errorf(mjs, ret, "wrong arg type");
11193
        goto clean;
11194
      default:
11195
        abort();
11196
        break;
11197
    }
11198
  }
11199
11200
  if (cbdata.userdata_idx >= 0 && cbdata.func_idx >= 0) {
11201
    struct mjs_ffi_cb_args *cbargs = NULL;
11202
    struct mjs_ffi_cb_args **pitem = NULL;
11203
11204
    /* the function takes a callback */
11205
11206
    /*
11207
     * Get cbargs: either reuse the existing one (if the matching item exists),
11208
     * or create a new one.
11209
     */
11210
    pitem = ffi_get_matching(&mjs->ffi_cb_args, cbdata.func, cbdata.userdata);
11211
    if (*pitem == NULL) {
11212
      /* No matching cbargs item; we need to add a new one */
11213
      cbargs = calloc(1, sizeof(*cbargs));
11214
      cbargs->mjs = mjs;
11215
      cbargs->func = cbdata.func;
11216
      cbargs->userdata = cbdata.userdata;
11217
      mjs_ffi_sig_copy(&cbargs->sig, psig->cb_sig);
11218
11219
      /* Establish a link to the newly allocated item */
11220
      *pitem = cbargs;
11221
    } else {
11222
      /* Found matching item: reuse it */
11223
      cbargs = *pitem;
11224
    }
11225
11226
    {
11227
      union {
11228
        ffi_fn_t *fn;
11229
        void *p;
11230
      } u;
11231
      u.fn = psig->cb_sig->fn;
11232
      ffi_set_ptr(&args[cbdata.func_idx], u.p);
11233
      ffi_set_ptr(&args[cbdata.userdata_idx], cbargs);
11234
    }
11235
  } else if (!(cbdata.userdata_idx == -1 && cbdata.func_idx == -1)) {
11236
    /*
11237
     * incomplete signature: it contains either the function pointer or
11238
     * userdata. It should contain both or none.
11239
     *
11240
     * It should be handled in mjs_parse_ffi_signature().
11241
     */
11242
    abort();
11243
  }
11244
11245
  ffi_call(psig->fn, nargs, &res, args);
11246
11247
  switch (rtype) {
11248
    case MJS_FFI_CTYPE_CHAR_PTR: {
11249
      const char *s = (const char *) (uintptr_t) res.v.i;
11250
      if (s != NULL) {
11251
        resv = mjs_mk_string(mjs, s, ~0, 1);
11252
      } else {
11253
        resv = MJS_NULL;
11254
      }
11255
      break;
11256
    }
11257
    case MJS_FFI_CTYPE_VOID_PTR:
11258
      resv = mjs_mk_foreign(mjs, (void *) (uintptr_t) res.v.i);
11259
      break;
11260
    case MJS_FFI_CTYPE_INT:
11261
      resv = mjs_mk_number(mjs, (int) res.v.i);
11262
      break;
11263
    case MJS_FFI_CTYPE_BOOL:
11264
      resv = mjs_mk_boolean(mjs, !!res.v.i);
11265
      break;
11266
    case MJS_FFI_CTYPE_DOUBLE:
11267
      resv = mjs_mk_number(mjs, res.v.d);
11268
      break;
11269
    case MJS_FFI_CTYPE_FLOAT:
11270
      resv = mjs_mk_number(mjs, res.v.f);
11271
      break;
11272
    default:
11273
      resv = mjs_mk_undefined();
11274
      break;
11275
  }
11276
11277
clean:
11278
  /*
11279
   * If there was some error, prepend an error message with the subject
11280
   * signature
11281
   */
11282
  if (ret != MJS_OK) {
11283
    mjs_prepend_errorf(mjs, ret, "failed to call FFIed function");
11284
    /* TODO(dfrank) stringify mjs_ffi_sig_t in some human-readable format */
11285
  }
11286
  mjs_return(mjs, resv);
11287
11288
  return ret;
11289
}
11290
11291
/*
11292
 * TODO(dfrank): make it return boolean (when booleans are supported), instead
11293
 * of a number
11294
 */
11295
MJS_PRIVATE void mjs_ffi_cb_free(struct mjs *mjs) {
11296
  mjs_val_t ret = mjs_mk_number(mjs, 0);
11297
  mjs_val_t func = mjs_arg(mjs, 0);
11298
  mjs_val_t userdata = mjs_arg(mjs, 1);
11299
11300
  if (mjs_is_function(func)) {
11301
    struct mjs_ffi_cb_args **pitem =
11302
        ffi_get_matching(&mjs->ffi_cb_args, func, userdata);
11303
    if (*pitem != NULL) {
11304
      /* Found matching item: remove it from the linked list, and free */
11305
      struct mjs_ffi_cb_args *cbargs = *pitem;
11306
      *pitem = cbargs->next;
11307
      mjs_ffi_sig_free(&cbargs->sig);
11308
      free(cbargs);
11309
      ret = mjs_mk_number(mjs, 1);
11310
    }
11311
  } else {
11312
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "missing argument 'func'");
11313
  }
11314
11315
  mjs_return(mjs, ret);
11316
}
11317
11318
78
void mjs_ffi_args_free_list(struct mjs *mjs) {
11319
78
  ffi_cb_args_t *next = mjs->ffi_cb_args;
11320
11321
156
  while (next != NULL) {
11322
    ffi_cb_args_t *cur = next;
11323
    next = next->next;
11324
    free(cur);
11325
  }
11326
78
}
11327
11328
MJS_PRIVATE void mjs_ffi_sig_init(mjs_ffi_sig_t *sig) {
11329
  memset(sig, 0, sizeof(*sig));
11330
}
11331
11332
MJS_PRIVATE void mjs_ffi_sig_copy(mjs_ffi_sig_t *to,
11333
                                  const mjs_ffi_sig_t *from) {
11334
  memcpy(to, from, sizeof(*to));
11335
  if (from->cb_sig != NULL) {
11336
    to->cb_sig = calloc(sizeof(*to->cb_sig), 1);
11337
    mjs_ffi_sig_copy(to->cb_sig, from->cb_sig);
11338
  }
11339
}
11340
11341
MJS_PRIVATE void mjs_ffi_sig_free(mjs_ffi_sig_t *sig) {
11342
  if (sig->cb_sig != NULL) {
11343
    free(sig->cb_sig);
11344
    sig->cb_sig = NULL;
11345
  }
11346
}
11347
11348
MJS_PRIVATE int mjs_ffi_sig_set_val_type(mjs_ffi_sig_t *sig, int idx,
11349
                                         mjs_ffi_ctype_t type) {
11350
  if (idx < MJS_CB_SIGNATURE_MAX_SIZE) {
11351
    sig->val_types[idx] = type;
11352
    return 1;
11353
  } else {
11354
    /* Index is too large */
11355
    return 0;
11356
  }
11357
}
11358
11359
MJS_PRIVATE int mjs_ffi_sig_validate(struct mjs *mjs, mjs_ffi_sig_t *sig,
11360
                                     enum ffi_sig_type sig_type) {
11361
  int ret = 0;
11362
  int i;
11363
  int callback_idx = 0;
11364
  int userdata_idx = 0;
11365
11366
  sig->is_valid = 0;
11367
11368
  switch (sig_type) {
11369
    case FFI_SIG_FUNC:
11370
      /* Make sure return type is fine */
11371
      if (sig->val_types[0] != MJS_FFI_CTYPE_NONE &&
11372
          sig->val_types[0] != MJS_FFI_CTYPE_INT &&
11373
          sig->val_types[0] != MJS_FFI_CTYPE_BOOL &&
11374
          sig->val_types[0] != MJS_FFI_CTYPE_DOUBLE &&
11375
          sig->val_types[0] != MJS_FFI_CTYPE_FLOAT &&
11376
          sig->val_types[0] != MJS_FFI_CTYPE_VOID_PTR &&
11377
          sig->val_types[0] != MJS_FFI_CTYPE_CHAR_PTR) {
11378
        mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "invalid return value type");
11379
        goto clean;
11380
      }
11381
      break;
11382
    case FFI_SIG_CALLBACK:
11383
      /* Make sure return type is fine */
11384
      if (sig->val_types[0] != MJS_FFI_CTYPE_NONE &&
11385
          sig->val_types[0] != MJS_FFI_CTYPE_INT &&
11386
          sig->val_types[0] != MJS_FFI_CTYPE_BOOL &&
11387
          sig->val_types[0] != MJS_FFI_CTYPE_DOUBLE &&
11388
          sig->val_types[0] != MJS_FFI_CTYPE_FLOAT &&
11389
          sig->val_types[0] != MJS_FFI_CTYPE_VOID_PTR) {
11390
        mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "invalid return value type");
11391
        goto clean;
11392
      }
11393
  }
11394
11395
  /* Handle argument types */
11396
  for (i = 1; i < MJS_CB_SIGNATURE_MAX_SIZE; i++) {
11397
    mjs_ffi_ctype_t type = sig->val_types[i];
11398
    switch (type) {
11399
      case MJS_FFI_CTYPE_USERDATA:
11400
        if (userdata_idx != 0) {
11401
          /* There must be at most one userdata arg, but we have more */
11402
          mjs_prepend_errorf(mjs, MJS_TYPE_ERROR,
11403
                             "more than one userdata arg: #%d and #%d",
11404
                             (userdata_idx - 1), (i - 1));
11405
          goto clean;
11406
        }
11407
        userdata_idx = i;
11408
        break;
11409
      case MJS_FFI_CTYPE_CALLBACK:
11410
        switch (sig_type) {
11411
          case FFI_SIG_FUNC:
11412
            break;
11413
          case FFI_SIG_CALLBACK:
11414
            mjs_prepend_errorf(mjs, MJS_TYPE_ERROR,
11415
                               "callback can't take another callback");
11416
            goto clean;
11417
        }
11418
        callback_idx = i;
11419
        break;
11420
      case MJS_FFI_CTYPE_INT:
11421
      case MJS_FFI_CTYPE_BOOL:
11422
      case MJS_FFI_CTYPE_VOID_PTR:
11423
      case MJS_FFI_CTYPE_CHAR_PTR:
11424
      case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR:
11425
      case MJS_FFI_CTYPE_DOUBLE:
11426
      case MJS_FFI_CTYPE_FLOAT:
11427
        /* Do nothing */
11428
        break;
11429
      case MJS_FFI_CTYPE_NONE:
11430
        /* No more arguments */
11431
        goto args_over;
11432
      default:
11433
        mjs_prepend_errorf(mjs, MJS_INTERNAL_ERROR, "invalid ffi_ctype: %d",
11434
                           type);
11435
        goto clean;
11436
    }
11437
11438
    sig->args_cnt++;
11439
  }
11440
args_over:
11441
11442
  switch (sig_type) {
11443
    case FFI_SIG_FUNC:
11444
      if (!((callback_idx > 0 && userdata_idx > 0) ||
11445
            (callback_idx == 0 && userdata_idx == 0))) {
11446
        mjs_prepend_errorf(mjs, MJS_TYPE_ERROR,
11447
                           "callback and userdata should be either both "
11448
                           "present or both absent");
11449
        goto clean;
11450
      }
11451
      break;
11452
    case FFI_SIG_CALLBACK:
11453
      if (userdata_idx == 0) {
11454
        /* No userdata arg */
11455
        mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "no userdata arg");
11456
        goto clean;
11457
      }
11458
      break;
11459
  }
11460
11461
  ret = 1;
11462
11463
clean:
11464
  if (ret) {
11465
    sig->is_valid = 1;
11466
  }
11467
  return ret;
11468
}
11469
11470
MJS_PRIVATE int mjs_ffi_is_regular_word(mjs_ffi_ctype_t type) {
11471
  switch (type) {
11472
    case MJS_FFI_CTYPE_INT:
11473
    case MJS_FFI_CTYPE_BOOL:
11474
      return 1;
11475
    default:
11476
      return 0;
11477
  }
11478
}
11479
11480
MJS_PRIVATE int mjs_ffi_is_regular_word_or_void(mjs_ffi_ctype_t type) {
11481
  return (type == MJS_FFI_CTYPE_NONE || mjs_ffi_is_regular_word(type));
11482
}
11483
11484
#ifdef _WIN32
11485
void *dlsym(void *handle, const char *name) {
11486
  static HANDLE msvcrt_dll;
11487
  void *sym = NULL;
11488
  if (msvcrt_dll == NULL) msvcrt_dll = GetModuleHandle("msvcrt.dll");
11489
  if ((sym = GetProcAddress(GetModuleHandle(NULL), name)) == NULL) {
11490
    sym = GetProcAddress(msvcrt_dll, name);
11491
  }
11492
  return sym;
11493
}
11494
#elif !defined(__unix__) && !defined(__APPLE__)
11495
void *dlsym(void *handle, const char *name) {
11496
  (void) handle;
11497
  (void) name;
11498
  return NULL;
11499
}
11500
#endif
11501
#ifdef MJS_MODULE_LINES
11502
#line 1 "mjs/src/mjs_gc.c"
11503
#endif
11504
/*
11505
 * Copyright (c) 2014 Cesanta Software Limited
11506
 * All rights reserved
11507
 */
11508
11509
#include <stdio.h>
11510
11511
/* Amalgamated: #include "common/cs_varint.h" */
11512
/* Amalgamated: #include "common/mbuf.h" */
11513
11514
/* Amalgamated: #include "mjs/src/mjs_core.h" */
11515
/* Amalgamated: #include "mjs/src/mjs_ffi.h" */
11516
/* Amalgamated: #include "mjs/src/mjs_gc.h" */
11517
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
11518
/* Amalgamated: #include "mjs/src/mjs_object.h" */
11519
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
11520
/* Amalgamated: #include "mjs/src/mjs_string.h" */
11521
11522
/*
11523
 * Macros for marking reachable things: use bit 0.
11524
 */
11525
#define MARK(p) (((struct gc_cell *) (p))->head.word |= 1)
11526
#define UNMARK(p) (((struct gc_cell *) (p))->head.word &= ~1)
11527
#define MARKED(p) (((struct gc_cell *) (p))->head.word & 1)
11528
11529
/*
11530
 * Similar to `MARK()` / `UNMARK()` / `MARKED()`, but `.._FREE` counterparts
11531
 * are intended to mark free cells (as opposed to used ones), so they use
11532
 * bit 1.
11533
 */
11534
#define MARK_FREE(p) (((struct gc_cell *) (p))->head.word |= 2)
11535
#define UNMARK_FREE(p) (((struct gc_cell *) (p))->head.word &= ~2)
11536
#define MARKED_FREE(p) (((struct gc_cell *) (p))->head.word & 2)
11537
11538
/*
11539
 * When each arena has that or less free cells, GC will be scheduled
11540
 */
11541
#define GC_ARENA_CELLS_RESERVE 2
11542
11543
static struct gc_block *gc_new_block(struct gc_arena *a, size_t size);
11544
static void gc_free_block(struct gc_block *b);
11545
static void gc_mark_mbuf_pt(struct mjs *mjs, const struct mbuf *mbuf);
11546
11547
235
MJS_PRIVATE struct mjs_object *new_object(struct mjs *mjs) {
11548
235
  return (struct mjs_object *) gc_alloc_cell(mjs, &mjs->object_arena);
11549
}
11550
11551
1405
MJS_PRIVATE struct mjs_property *new_property(struct mjs *mjs) {
11552
1405
  return (struct mjs_property *) gc_alloc_cell(mjs, &mjs->property_arena);
11553
}
11554
11555
MJS_PRIVATE struct mjs_ffi_sig *new_ffi_sig(struct mjs *mjs) {
11556
  return (struct mjs_ffi_sig *) gc_alloc_cell(mjs, &mjs->ffi_sig_arena);
11557
}
11558
11559
/* Initializes a new arena. */
11560
234
MJS_PRIVATE void gc_arena_init(struct gc_arena *a, size_t cell_size,
11561
                               size_t initial_size, size_t size_increment) {
11562
234
  assert(cell_size >= sizeof(uintptr_t));
11563
11564
234
  memset(a, 0, sizeof(*a));
11565
234
  a->cell_size = cell_size;
11566
234
  a->size_increment = size_increment;
11567
234
  a->blocks = gc_new_block(a, initial_size);
11568
234
}
11569
11570
234
MJS_PRIVATE void gc_arena_destroy(struct mjs *mjs, struct gc_arena *a) {
11571
  struct gc_block *b;
11572
11573
234
  if (a->blocks != NULL) {
11574
234
    gc_sweep(mjs, a, 0);
11575
702
    for (b = a->blocks; b != NULL;) {
11576
      struct gc_block *tmp;
11577
234
      tmp = b;
11578
234
      b = b->next;
11579
234
      gc_free_block(tmp);
11580
    }
11581
  }
11582
234
}
11583
11584
234
static void gc_free_block(struct gc_block *b) {
11585
234
  free(b->base);
11586
234
  free(b);
11587
234
}
11588
11589
234
static struct gc_block *gc_new_block(struct gc_arena *a, size_t size) {
11590
  struct gc_cell *cur;
11591
  struct gc_block *b;
11592
11593
234
  b = (struct gc_block *) calloc(1, sizeof(*b));
11594
234
  if (b == NULL) abort();
11595
11596
234
  b->size = size;
11597
234
  b->base = (struct gc_cell *) calloc(a->cell_size, b->size);
11598
234
  if (b->base == NULL) abort();
11599
11600
5148
  for (cur = GC_CELL_OP(a, b->base, +, 0);
11601
4914
       cur < GC_CELL_OP(a, b->base, +, b->size);
11602
4680
       cur = GC_CELL_OP(a, cur, +, 1)) {
11603
4680
    cur->head.link = a->free;
11604
4680
    a->free = cur;
11605
  }
11606
11607
234
  return b;
11608
}
11609
11610
/*
11611
 * Returns whether the given arena has GC_ARENA_CELLS_RESERVE or less free
11612
 * cells
11613
 */
11614
1640
static int gc_arena_is_gc_needed(struct gc_arena *a) {
11615
1640
  struct gc_cell *r = a->free;
11616
  int i;
11617
11618
6480
  for (i = 0; i <= GC_ARENA_CELLS_RESERVE; i++, r = r->head.link) {
11619
4919
    if (r == NULL) {
11620
79
      return 1;
11621
    }
11622
  }
11623
11624
1561
  return 0;
11625
}
11626
11627
472
MJS_PRIVATE int gc_strings_is_gc_needed(struct mjs *mjs) {
11628
472
  struct mbuf *m = &mjs->owned_strings;
11629
472
  return (double) m->len / (double) m->size > 0.9;
11630
}
11631
11632
1640
MJS_PRIVATE void *gc_alloc_cell(struct mjs *mjs, struct gc_arena *a) {
11633
  struct gc_cell *r;
11634
11635
1640
  if (a->free == NULL) {
11636
    struct gc_block *b = gc_new_block(a, a->size_increment);
11637
    b->next = a->blocks;
11638
    a->blocks = b;
11639
  }
11640
1640
  r = a->free;
11641
11642
1640
  UNMARK(r);
11643
11644
1640
  a->free = r->head.link;
11645
11646
#if MJS_MEMORY_STATS
11647
  a->allocations++;
11648
  a->alive++;
11649
#endif
11650
11651
  /* Schedule GC if needed */
11652
1640
  if (gc_arena_is_gc_needed(a)) {
11653
79
    mjs->need_gc = 1;
11654
  }
11655
11656
  /*
11657
   * TODO(mkm): minor opt possible since most of the fields
11658
   * are overwritten downstream, but not worth the yak shave time
11659
   * when fields are added to GC-able structures */
11660
1640
  memset(r, 0, a->cell_size);
11661
1640
  return (void *) r;
11662
}
11663
11664
/*
11665
 * Scans the arena and add all unmarked cells to the free list.
11666
 *
11667
 * Empty blocks get deallocated. The head of the free list will contais cells
11668
 * from the last (oldest) block. Cells will thus be allocated in block order.
11669
 */
11670
435
void gc_sweep(struct mjs *mjs, struct gc_arena *a, size_t start) {
11671
  struct gc_block *b;
11672
  struct gc_cell *cur;
11673
435
  struct gc_block **prevp = &a->blocks;
11674
#if MJS_MEMORY_STATS
11675
  a->alive = 0;
11676
#endif
11677
11678
  /*
11679
   * Before we sweep, we should mark all free cells in a way that is
11680
   * distinguishable from marked used cells.
11681
   */
11682
  {
11683
    struct gc_cell *next;
11684
6087
    for (cur = a->free; cur != NULL; cur = next) {
11685
5652
      next = cur->head.link;
11686
5652
      MARK_FREE(cur);
11687
    }
11688
  }
11689
11690
  /*
11691
   * We'll rebuild the whole `free` list, so initially we just reset it
11692
   */
11693
435
  a->free = NULL;
11694
11695
1305
  for (b = a->blocks; b != NULL;) {
11696
435
    size_t freed_in_block = 0;
11697
    /*
11698
     * if it turns out that this block is 100% garbage
11699
     * we can release the whole block, but the addition
11700
     * of it's cells to the free list has to be undone.
11701
     */
11702
435
    struct gc_cell *prev_free = a->free;
11703
11704
9570
    for (cur = GC_CELL_OP(a, b->base, +, start);
11705
9135
         cur < GC_CELL_OP(a, b->base, +, b->size);
11706
8700
         cur = GC_CELL_OP(a, cur, +, 1)) {
11707
8700
      if (MARKED(cur)) {
11708
        /* The cell is used and marked  */
11709
1408
        UNMARK(cur);
11710
#if MJS_MEMORY_STATS
11711
        a->alive++;
11712
#endif
11713
      } else {
11714
        /*
11715
         * The cell is either:
11716
         * - free
11717
         * - garbage that's about to be freed
11718
         */
11719
11720
7292
        if (MARKED_FREE(cur)) {
11721
          /* The cell is free, so, just unmark it */
11722
5652
          UNMARK_FREE(cur);
11723
        } else {
11724
          /*
11725
           * The cell is used and should be freed: call the destructor and
11726
           * reset the memory
11727
           */
11728
1640
          if (a->destructor != NULL) {
11729
            a->destructor(mjs, cur);
11730
          }
11731
1640
          memset(cur, 0, a->cell_size);
11732
        }
11733
11734
        /* Add this cell to the `free` list */
11735
7292
        cur->head.link = a->free;
11736
7292
        a->free = cur;
11737
7292
        freed_in_block++;
11738
#if MJS_MEMORY_STATS
11739
        a->garbage++;
11740
#endif
11741
      }
11742
    }
11743
11744
    /*
11745
     * don't free the initial block, which is at the tail
11746
     * because it has a special size aimed at reducing waste
11747
     * and simplifying initial startup. TODO(mkm): improve
11748
     * */
11749

435
    if (b->next != NULL && freed_in_block == b->size) {
11750
      *prevp = b->next;
11751
      gc_free_block(b);
11752
      b = *prevp;
11753
      a->free = prev_free;
11754
    } else {
11755
435
      prevp = &b->next;
11756
435
      b = b->next;
11757
    }
11758
  }
11759
435
}
11760
11761
/* Mark an FFI signature */
11762
static void gc_mark_ffi_sig(struct mjs *mjs, mjs_val_t *v) {
11763
  struct mjs_ffi_sig *psig;
11764
11765
  assert(mjs_is_ffi_sig(*v));
11766
11767
  psig = mjs_get_ffi_sig_struct(*v);
11768
11769
  /*
11770
   * we treat all object like things like objects but they might be functions,
11771
   * gc_check_val checks the appropriate arena per actual value type.
11772
   */
11773
  if (!gc_check_val(mjs, *v)) {
11774
    abort();
11775
  }
11776
11777
  if (MARKED(psig)) return;
11778
11779
  MARK(psig);
11780
}
11781
11782
/* Mark an object */
11783
268
static void gc_mark_object(struct mjs *mjs, mjs_val_t *v) {
11784
  struct mjs_object *obj_base;
11785
  struct mjs_property *prop;
11786
  struct mjs_property *next;
11787
11788
268
  assert(mjs_is_object(*v));
11789
11790
268
  obj_base = get_object_struct(*v);
11791
11792
  /*
11793
   * we treat all object like things like objects but they might be functions,
11794
   * gc_check_val checks the appropriate arena per actual value type.
11795
   */
11796
268
  if (!gc_check_val(mjs, *v)) {
11797
    abort();
11798
  }
11799
11800
268
  if (MARKED(obj_base)) return;
11801
11802
  /* mark object itself, and its properties */
11803
1609
  for ((prop = obj_base->properties), MARK(obj_base); prop != NULL;
11804
1207
       prop = next) {
11805
1207
    if (!gc_check_ptr(&mjs->property_arena, prop)) {
11806
      abort();
11807
    }
11808
11809
1207
    gc_mark(mjs, &prop->name);
11810
1207
    gc_mark(mjs, &prop->value);
11811
11812
1207
    next = prop->next;
11813
1207
    MARK(prop);
11814
  }
11815
11816
  /* mark object's prototype */
11817
  /*
11818
   * We dropped support for object prototypes in MJS.
11819
   * If we ever bring it back, don't forget to mark it
11820
   */
11821
  /* gc_mark(mjs, mjs_get_proto(mjs, v)); */
11822
}
11823
11824
/* Mark a string value */
11825
402
static void gc_mark_string(struct mjs *mjs, mjs_val_t *v) {
11826
402
  mjs_val_t h, tmp = 0;
11827
  char *s;
11828
11829
  /* clang-format off */
11830
11831
  /*
11832
   * If a value points to an unmarked string we shall:
11833
   *  1. save the first 6 bytes of the string
11834
   *     since we need to be able to distinguish real values from
11835
   *     the saved first 6 bytes of the string, we need to tag the chunk
11836
   *     as MJS_TAG_STRING_C
11837
   *  2. encode value's address (v) into the first 6 bytes of the string.
11838
   *  3. put the saved 8 bytes (tag + chunk) back into the value.
11839
   *  4. mark the string by putting '\1' in the NUL terminator of the previous
11840
   *     string chunk.
11841
   *
11842
   * If a value points to an already marked string we shall:
11843
   *     (0, <6 bytes of a pointer to a mjs_val_t>), hence we have to skip
11844
   *     the first byte. We tag the value pointer as a MJS_TAG_FOREIGN
11845
   *     so that it won't be followed during recursive mark.
11846
   *
11847
   *  ... the rest is the same
11848
   *
11849
   *  Note: 64-bit pointers can be represented with 48-bits
11850
   */
11851
11852
  /* clang-format on */
11853
11854
402
  assert((*v & MJS_TAG_MASK) == MJS_TAG_STRING_O);
11855
11856
402
  s = mjs->owned_strings.buf + gc_string_mjs_val_to_offset(*v);
11857
402
  assert(s < mjs->owned_strings.buf + mjs->owned_strings.len);
11858
402
  if (s[-1] == '\0') {
11859
402
    memcpy(&tmp, s, sizeof(tmp) - 2);
11860
402
    tmp |= MJS_TAG_STRING_C;
11861
  } else {
11862
    memcpy(&tmp, s, sizeof(tmp) - 2);
11863
    tmp |= MJS_TAG_FOREIGN;
11864
  }
11865
11866
402
  h = (mjs_val_t)(uintptr_t) v;
11867
402
  s[-1] = 1;
11868
402
  memcpy(s, &h, sizeof(h) - 2);
11869
402
  memcpy(v, &tmp, sizeof(tmp));
11870
402
}
11871
11872
2682
MJS_PRIVATE void gc_mark(struct mjs *mjs, mjs_val_t *v) {
11873
2682
  if (mjs_is_object(*v)) {
11874
268
    gc_mark_object(mjs, v);
11875
  }
11876
2682
  if (mjs_is_ffi_sig(*v)) {
11877
    gc_mark_ffi_sig(mjs, v);
11878
  }
11879
2682
  if ((*v & MJS_TAG_MASK) == MJS_TAG_STRING_O) {
11880
402
    gc_mark_string(mjs, v);
11881
  }
11882
2682
}
11883
11884
3151
MJS_PRIVATE uint64_t gc_string_mjs_val_to_offset(mjs_val_t v) {
11885
3151
  return (((uint64_t)(uintptr_t) get_ptr(v)) & ~MJS_TAG_MASK);
11886
}
11887
11888
402
MJS_PRIVATE mjs_val_t gc_string_val_from_offset(uint64_t s) {
11889
402
  return s | MJS_TAG_STRING_O;
11890
}
11891
11892
67
void gc_compact_strings(struct mjs *mjs) {
11893
67
  char *p = mjs->owned_strings.buf + 1;
11894
67
  uint64_t h, next, head = 1;
11895
  int len, llen;
11896
11897
536
  while (p < mjs->owned_strings.buf + mjs->owned_strings.len) {
11898
402
    if (p[-1] == '\1') {
11899
      /* relocate and update ptrs */
11900
402
      h = 0;
11901
402
      memcpy(&h, p, sizeof(h) - 2);
11902
11903
      /*
11904
       * relocate pointers until we find the tail.
11905
       * The tail is marked with MJS_TAG_STRING_C,
11906
       * while mjs_val_t link pointers are tagged with MJS_TAG_FOREIGN
11907
       */
11908
804
      for (; (h & MJS_TAG_MASK) != MJS_TAG_STRING_C; h = next) {
11909
402
        h &= ~MJS_TAG_MASK;
11910
402
        memcpy(&next, (char *) (uintptr_t) h, sizeof(h));
11911
11912
402
        *(mjs_val_t *) (uintptr_t) h = gc_string_val_from_offset(head);
11913
      }
11914
402
      h &= ~MJS_TAG_MASK;
11915
11916
      /*
11917
       * the tail contains the first 6 bytes we stole from
11918
       * the actual string.
11919
       */
11920
402
      len = cs_varint_decode_unsafe((unsigned char *) &h, &llen);
11921
402
      len += llen + 1;
11922
11923
      /*
11924
       * restore the saved 6 bytes
11925
       * TODO(mkm): think about endianness
11926
       */
11927
402
      memcpy(p, &h, sizeof(h) - 2);
11928
11929
      /*
11930
       * and relocate the string data by packing it to the left.
11931
       */
11932
402
      memmove(mjs->owned_strings.buf + head, p, len);
11933
402
      mjs->owned_strings.buf[head - 1] = 0x0;
11934
402
      p += len;
11935
402
      head += len;
11936
    } else {
11937
      len = cs_varint_decode_unsafe((unsigned char *) p, &llen);
11938
      len += llen + 1;
11939
11940
      p += len;
11941
    }
11942
  }
11943
11944
67
  mjs->owned_strings.len = head;
11945
67
}
11946
11947
67
MJS_PRIVATE int maybe_gc(struct mjs *mjs) {
11948
67
  if (!mjs->inhibit_gc) {
11949
67
    mjs_gc(mjs, 0);
11950
67
    return 1;
11951
  }
11952
  return 0;
11953
}
11954
11955
/*
11956
 * mark an array of `mjs_val_t` values (*not pointers* to them)
11957
 */
11958
268
static void gc_mark_val_array(struct mjs *mjs, mjs_val_t *vals, size_t len) {
11959
  mjs_val_t *vp;
11960
536
  for (vp = vals; vp < vals + len; vp++) {
11961
268
    gc_mark(mjs, vp);
11962
  }
11963
268
}
11964
11965
/*
11966
 * mark an mbuf containing *pointers* to `mjs_val_t` values
11967
 */
11968
67
static void gc_mark_mbuf_pt(struct mjs *mjs, const struct mbuf *mbuf) {
11969
  mjs_val_t **vp;
11970
134
  for (vp = (mjs_val_t **) mbuf->buf; (char *) vp < mbuf->buf + mbuf->len;
11971
       vp++) {
11972
    gc_mark(mjs, *vp);
11973
  }
11974
67
}
11975
11976
/*
11977
 * mark an mbuf containing `mjs_val_t` values (*not pointers* to them)
11978
 */
11979
201
static void gc_mark_mbuf_val(struct mjs *mjs, const struct mbuf *mbuf) {
11980
201
  gc_mark_val_array(mjs, (mjs_val_t *) mbuf->buf,
11981
201
                    mbuf->len / sizeof(mjs_val_t));
11982
201
}
11983
11984
67
static void gc_mark_ffi_cbargs_list(struct mjs *mjs, ffi_cb_args_t *cbargs) {
11985
67
  for (; cbargs != NULL; cbargs = cbargs->next) {
11986
    gc_mark(mjs, &cbargs->func);
11987
    gc_mark(mjs, &cbargs->userdata);
11988
  }
11989
67
}
11990
11991
/* Perform garbage collection */
11992
67
void mjs_gc(struct mjs *mjs, int full) {
11993
67
  gc_mark_val_array(mjs, (mjs_val_t *) &mjs->vals,
11994
                    sizeof(mjs->vals) / sizeof(mjs_val_t));
11995
11996
67
  gc_mark_mbuf_pt(mjs, &mjs->owned_values);
11997
67
  gc_mark_mbuf_val(mjs, &mjs->scopes);
11998
67
  gc_mark_mbuf_val(mjs, &mjs->stack);
11999
67
  gc_mark_mbuf_val(mjs, &mjs->call_stack);
12000
12001
67
  gc_mark_ffi_cbargs_list(mjs, mjs->ffi_cb_args);
12002
12003
67
  gc_compact_strings(mjs);
12004
12005
67
  gc_sweep(mjs, &mjs->object_arena, 0);
12006
67
  gc_sweep(mjs, &mjs->property_arena, 0);
12007
67
  gc_sweep(mjs, &mjs->ffi_sig_arena, 0);
12008
12009
67
  if (full) {
12010
    /*
12011
     * In case of full GC, we also resize strings buffer, but we still leave
12012
     * some extra space (at most, `_MJS_STRING_BUF_RESERVE`) in order to avoid
12013
     * frequent reallocations
12014
     */
12015
    size_t trimmed_size = mjs->owned_strings.len + _MJS_STRING_BUF_RESERVE;
12016
    if (trimmed_size < mjs->owned_strings.size) {
12017
      mbuf_resize(&mjs->owned_strings, trimmed_size);
12018
    }
12019
  }
12020
67
}
12021
12022
268
MJS_PRIVATE int gc_check_val(struct mjs *mjs, mjs_val_t v) {
12023
268
  if (mjs_is_object(v)) {
12024
268
    return gc_check_ptr(&mjs->object_arena, get_object_struct(v));
12025
  }
12026
  if (mjs_is_ffi_sig(v)) {
12027
    return gc_check_ptr(&mjs->ffi_sig_arena, mjs_get_ffi_sig_struct(v));
12028
  }
12029
  return 1;
12030
}
12031
12032
1475
MJS_PRIVATE int gc_check_ptr(const struct gc_arena *a, const void *ptr) {
12033
1475
  const struct gc_cell *p = (const struct gc_cell *) ptr;
12034
  struct gc_block *b;
12035
1475
  for (b = a->blocks; b != NULL; b = b->next) {
12036

1475
    if (p >= b->base && p < GC_CELL_OP(a, b->base, +, b->size)) {
12037
1475
      return 1;
12038
    }
12039
  }
12040
  return 0;
12041
}
12042
#ifdef MJS_MODULE_LINES
12043
#line 1 "mjs/src/mjs_json.c"
12044
#endif
12045
/*
12046
 * Copyright (c) 2016 Cesanta Software Limited
12047
 * All rights reserved
12048
 */
12049
12050
/* Amalgamated: #include "common/str_util.h" */
12051
/* Amalgamated: #include "frozen.h" */
12052
/* Amalgamated: #include "mjs/src/mjs_array.h" */
12053
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
12054
/* Amalgamated: #include "mjs/src/mjs_conversion.h" */
12055
/* Amalgamated: #include "mjs/src/mjs_core.h" */
12056
/* Amalgamated: #include "mjs/src/mjs_object.h" */
12057
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
12058
/* Amalgamated: #include "mjs/src/mjs_string.h" */
12059
12060
#define BUF_LEFT(size, used) (((size_t)(used) < (size)) ? ((size) - (used)) : 0)
12061
12062
/*
12063
 * Returns whether the value of given type should be skipped when generating
12064
 * JSON output
12065
 *
12066
 * So far it always returns 0, but we might add some logic later, if we
12067
 * implement some non-jsonnable objects
12068
 */
12069
static int should_skip_for_json(enum mjs_type type) {
12070
  int ret;
12071
  switch (type) {
12072
    /* All permitted values */
12073
    case MJS_TYPE_NULL:
12074
    case MJS_TYPE_BOOLEAN:
12075
    case MJS_TYPE_NUMBER:
12076
    case MJS_TYPE_STRING:
12077
    case MJS_TYPE_OBJECT_GENERIC:
12078
    case MJS_TYPE_OBJECT_ARRAY:
12079
      ret = 0;
12080
      break;
12081
    default:
12082
      ret = 1;
12083
      break;
12084
  }
12085
  return ret;
12086
}
12087
12088
static const char *hex_digits = "0123456789abcdef";
12089
static char *append_hex(char *buf, char *limit, uint8_t c) {
12090
  if (buf < limit) *buf++ = 'u';
12091
  if (buf < limit) *buf++ = '0';
12092
  if (buf < limit) *buf++ = '0';
12093
  if (buf < limit) *buf++ = hex_digits[(int) ((c >> 4) % 0xf)];
12094
  if (buf < limit) *buf++ = hex_digits[(int) (c & 0xf)];
12095
  return buf;
12096
}
12097
12098
/*
12099
 * Appends quoted s to buf. Any double quote contained in s will be escaped.
12100
 * Returns the number of characters that would have been added,
12101
 * like snprintf.
12102
 * If size is zero it doesn't output anything but keeps counting.
12103
 */
12104
static int snquote(char *buf, size_t size, const char *s, size_t len) {
12105
  char *limit = buf + size;
12106
  const char *end;
12107
  /*
12108
   * String single character escape sequence:
12109
   * http://www.ecma-international.org/ecma-262/6.0/index.html#table-34
12110
   *
12111
   * 0x8 -> \b
12112
   * 0x9 -> \t
12113
   * 0xa -> \n
12114
   * 0xb -> \v
12115
   * 0xc -> \f
12116
   * 0xd -> \r
12117
   */
12118
  const char *specials = "btnvfr";
12119
  size_t i = 0;
12120
12121
  i++;
12122
  if (buf < limit) *buf++ = '"';
12123
12124
  for (end = s + len; s < end; s++) {
12125
    if (*s == '"' || *s == '\\') {
12126
      i++;
12127
      if (buf < limit) *buf++ = '\\';
12128
    } else if (*s >= '\b' && *s <= '\r') {
12129
      i += 2;
12130
      if (buf < limit) *buf++ = '\\';
12131
      if (buf < limit) *buf++ = specials[*s - '\b'];
12132
      continue;
12133
    } else if ((unsigned char) *s < '\b' || (*s > '\r' && *s < ' ')) {
12134
      i += 6 /* \uXXXX */;
12135
      if (buf < limit) *buf++ = '\\';
12136
      buf = append_hex(buf, limit, (uint8_t) *s);
12137
      continue;
12138
    }
12139
    i++;
12140
    if (buf < limit) *buf++ = *s;
12141
  }
12142
12143
  i++;
12144
  if (buf < limit) *buf++ = '"';
12145
12146
  if (buf < limit) {
12147
    *buf = '\0';
12148
  } else if (size != 0) {
12149
    /*
12150
     * There is no room for the NULL char, but the size wasn't zero, so we can
12151
     * safely put NULL in the previous byte
12152
     */
12153
    *(buf - 1) = '\0';
12154
  }
12155
  return i;
12156
}
12157
12158
MJS_PRIVATE mjs_err_t to_json_or_debug(struct mjs *mjs, mjs_val_t v, char *buf,
12159
                                       size_t size, size_t *res_len,
12160
                                       uint8_t is_debug) {
12161
  mjs_val_t el;
12162
  char *vp;
12163
  mjs_err_t rcode = MJS_OK;
12164
  size_t len = 0;
12165
  /*
12166
   * TODO(dfrank) : also push all `mjs_val_t`s that are declared below
12167
   */
12168
12169
  if (size > 0) *buf = '\0';
12170
12171
  if (!is_debug && should_skip_for_json(mjs_get_type(v))) {
12172
    goto clean;
12173
  }
12174
12175
  for (vp = mjs->json_visited_stack.buf;
12176
       vp < mjs->json_visited_stack.buf + mjs->json_visited_stack.len;
12177
       vp += sizeof(mjs_val_t)) {
12178
    if (*(mjs_val_t *) vp == v) {
12179
      strncpy(buf, "[Circular]", size);
12180
      len = 10;
12181
      goto clean;
12182
    }
12183
  }
12184
12185
  switch (mjs_get_type(v)) {
12186
    case MJS_TYPE_NULL:
12187
    case MJS_TYPE_BOOLEAN:
12188
    case MJS_TYPE_NUMBER:
12189
    case MJS_TYPE_UNDEFINED:
12190
    case MJS_TYPE_FOREIGN:
12191
      /* For those types, regular `mjs_to_string()` works */
12192
      {
12193
        /* TODO: refactor: mjs_to_string allocates memory every time */
12194
        char *p = NULL;
12195
        int need_free = 0;
12196
        rcode = mjs_to_string(mjs, &v, &p, &len, &need_free);
12197
        c_snprintf(buf, size, "%.*s", (int) len, p);
12198
        if (need_free) {
12199
          free(p);
12200
        }
12201
      }
12202
      goto clean;
12203
12204
    case MJS_TYPE_STRING: {
12205
      /*
12206
       * For strings we can't just use `primitive_to_str()`, because we need
12207
       * quoted value
12208
       */
12209
      size_t n;
12210
      const char *str = mjs_get_string(mjs, &v, &n);
12211
      len = snquote(buf, size, str, n);
12212
      goto clean;
12213
    }
12214
12215
    case MJS_TYPE_OBJECT_FUNCTION:
12216
    case MJS_TYPE_OBJECT_GENERIC: {
12217
      char *b = buf;
12218
      struct mjs_property *prop = NULL;
12219
      struct mjs_object *o = NULL;
12220
12221
      mbuf_append(&mjs->json_visited_stack, (char *) &v, sizeof(v));
12222
      b += c_snprintf(b, BUF_LEFT(size, b - buf), "{");
12223
      o = get_object_struct(v);
12224
      for (prop = o->properties; prop != NULL; prop = prop->next) {
12225
        size_t n;
12226
        const char *s;
12227
        if (!is_debug && should_skip_for_json(mjs_get_type(prop->value))) {
12228
          continue;
12229
        }
12230
        if (b - buf != 1) { /* Not the first property to be printed */
12231
          b += c_snprintf(b, BUF_LEFT(size, b - buf), ",");
12232
        }
12233
        s = mjs_get_string(mjs, &prop->name, &n);
12234
        b += c_snprintf(b, BUF_LEFT(size, b - buf), "\"%.*s\":", (int) n, s);
12235
        {
12236
          size_t tmp = 0;
12237
          rcode = to_json_or_debug(mjs, prop->value, b, BUF_LEFT(size, b - buf),
12238
                                   &tmp, is_debug);
12239
          if (rcode != MJS_OK) {
12240
            goto clean_iter;
12241
          }
12242
          b += tmp;
12243
        }
12244
      }
12245
12246
      b += c_snprintf(b, BUF_LEFT(size, b - buf), "}");
12247
      mjs->json_visited_stack.len -= sizeof(v);
12248
12249
    clean_iter:
12250
      len = b - buf;
12251
      goto clean;
12252
    }
12253
    case MJS_TYPE_OBJECT_ARRAY: {
12254
      int has;
12255
      char *b = buf;
12256
      size_t i, alen = mjs_array_length(mjs, v);
12257
      mbuf_append(&mjs->json_visited_stack, (char *) &v, sizeof(v));
12258
      b += c_snprintf(b, BUF_LEFT(size, b - buf), "[");
12259
      for (i = 0; i < alen; i++) {
12260
        el = mjs_array_get2(mjs, v, i, &has);
12261
        if (has) {
12262
          size_t tmp = 0;
12263
          if (!is_debug && should_skip_for_json(mjs_get_type(el))) {
12264
            b += c_snprintf(b, BUF_LEFT(size, b - buf), "null");
12265
          } else {
12266
            rcode = to_json_or_debug(mjs, el, b, BUF_LEFT(size, b - buf), &tmp,
12267
                                     is_debug);
12268
            if (rcode != MJS_OK) {
12269
              goto clean;
12270
            }
12271
          }
12272
          b += tmp;
12273
        } else {
12274
          b += c_snprintf(b, BUF_LEFT(size, b - buf), "null");
12275
        }
12276
        if (i != alen - 1) {
12277
          b += c_snprintf(b, BUF_LEFT(size, b - buf), ",");
12278
        }
12279
      }
12280
      b += c_snprintf(b, BUF_LEFT(size, b - buf), "]");
12281
      mjs->json_visited_stack.len -= sizeof(v);
12282
      len = b - buf;
12283
      goto clean;
12284
    }
12285
12286
    case MJS_TYPES_CNT:
12287
      abort();
12288
  }
12289
12290
  abort();
12291
12292
  len = 0; /* for compilers that don't know about abort() */
12293
  goto clean;
12294
12295
clean:
12296
  if (rcode != MJS_OK) {
12297
    len = 0;
12298
  }
12299
  if (res_len != NULL) {
12300
    *res_len = len;
12301
  }
12302
  return rcode;
12303
}
12304
12305
MJS_PRIVATE mjs_err_t mjs_json_stringify(struct mjs *mjs, mjs_val_t v,
12306
                                         char *buf, size_t size, char **res) {
12307
  mjs_err_t rcode = MJS_OK;
12308
  char *p = buf;
12309
  size_t len;
12310
12311
  to_json_or_debug(mjs, v, buf, size, &len, 0);
12312
12313
  if (len >= size) {
12314
    /* Buffer is not large enough. Allocate a bigger one */
12315
    p = (char *) malloc(len + 1);
12316
    rcode = mjs_json_stringify(mjs, v, p, len + 1, res);
12317
    assert(*res == p);
12318
    goto clean;
12319
  } else {
12320
    *res = p;
12321
    goto clean;
12322
  }
12323
12324
clean:
12325
  /*
12326
   * If we're going to return an error, and we allocated a buffer, then free
12327
   * it. Otherwise, caller should free it.
12328
   */
12329
  if (rcode != MJS_OK && p != buf) {
12330
    free(p);
12331
  }
12332
  return rcode;
12333
}
12334
12335
/*
12336
 * JSON parsing frame: a separate frame is allocated for each nested
12337
 * object/array during parsing
12338
 */
12339
struct json_parse_frame {
12340
  mjs_val_t val;
12341
  struct json_parse_frame *up;
12342
};
12343
12344
/*
12345
 * Context for JSON parsing by means of json_walk()
12346
 */
12347
struct json_parse_ctx {
12348
  struct mjs *mjs;
12349
  mjs_val_t result;
12350
  struct json_parse_frame *frame;
12351
  enum mjs_err rcode;
12352
};
12353
12354
/* Allocate JSON parse frame */
12355
static struct json_parse_frame *alloc_json_frame(struct json_parse_ctx *ctx,
12356
                                                 mjs_val_t v) {
12357
  struct json_parse_frame *frame =
12358
      (struct json_parse_frame *) calloc(sizeof(struct json_parse_frame), 1);
12359
  frame->val = v;
12360
  mjs_own(ctx->mjs, &frame->val);
12361
  return frame;
12362
}
12363
12364
/* Free JSON parse frame, return the previous one (which may be NULL) */
12365
static struct json_parse_frame *free_json_frame(
12366
    struct json_parse_ctx *ctx, struct json_parse_frame *frame) {
12367
  struct json_parse_frame *up = frame->up;
12368
  mjs_disown(ctx->mjs, &frame->val);
12369
  free(frame);
12370
  return up;
12371
}
12372
12373
/* Callback for json_walk() */
12374
static void frozen_cb(void *data, const char *name, size_t name_len,
12375
                      const char *path, const struct json_token *token) {
12376
  struct json_parse_ctx *ctx = (struct json_parse_ctx *) data;
12377
  mjs_val_t v = MJS_UNDEFINED;
12378
12379
  (void) path;
12380
12381
  mjs_own(ctx->mjs, &v);
12382
12383
  switch (token->type) {
12384
    case JSON_TYPE_STRING: {
12385
      char *dst;
12386
      if (token->len > 0 && (dst = malloc(token->len)) != NULL) {
12387
        int len = json_unescape(token->ptr, token->len, dst, token->len);
12388
        if (len < 0) {
12389
          mjs_prepend_errorf(ctx->mjs, MJS_TYPE_ERROR, "invalid JSON string");
12390
          break;
12391
        }
12392
        v = mjs_mk_string(ctx->mjs, dst, len, 1 /* copy */);
12393
        free(dst);
12394
      } else {
12395
        /*
12396
         * This branch is for 0-len strings, and for malloc errors
12397
         * TODO(lsm): on malloc error, propagate the error upstream
12398
         */
12399
        v = mjs_mk_string(ctx->mjs, "", 0, 1 /* copy */);
12400
      }
12401
      break;
12402
    }
12403
    case JSON_TYPE_NUMBER:
12404
      v = mjs_mk_number(ctx->mjs, strtod(token->ptr, NULL));
12405
      break;
12406
    case JSON_TYPE_TRUE:
12407
      v = mjs_mk_boolean(ctx->mjs, 1);
12408
      break;
12409
    case JSON_TYPE_FALSE:
12410
      v = mjs_mk_boolean(ctx->mjs, 0);
12411
      break;
12412
    case JSON_TYPE_NULL:
12413
      v = MJS_NULL;
12414
      break;
12415
    case JSON_TYPE_OBJECT_START:
12416
      v = mjs_mk_object(ctx->mjs);
12417
      break;
12418
    case JSON_TYPE_ARRAY_START:
12419
      v = mjs_mk_array(ctx->mjs);
12420
      break;
12421
12422
    case JSON_TYPE_OBJECT_END:
12423
    case JSON_TYPE_ARRAY_END: {
12424
      /* Object or array has finished: deallocate its frame */
12425
      ctx->frame = free_json_frame(ctx, ctx->frame);
12426
    } break;
12427
12428
    default:
12429
      LOG(LL_ERROR, ("Wrong token type %d\n", token->type));
12430
      break;
12431
  }
12432
12433
  if (!mjs_is_undefined(v)) {
12434
    if (name != NULL && name_len != 0) {
12435
      /* Need to define a property on the current object/array */
12436
      if (mjs_is_object(ctx->frame->val)) {
12437
        mjs_set(ctx->mjs, ctx->frame->val, name, name_len, v);
12438
      } else if (mjs_is_array(ctx->frame->val)) {
12439
        /*
12440
         * TODO(dfrank): consult name_len. Currently it's not a problem due to
12441
         * the implementation details of frozen, but it might change
12442
         */
12443
        int idx = (int) strtod(name, NULL);
12444
        mjs_array_set(ctx->mjs, ctx->frame->val, idx, v);
12445
      } else {
12446
        LOG(LL_ERROR, ("Current value is neither object nor array\n"));
12447
      }
12448
    } else {
12449
      /* This is a root value */
12450
      assert(ctx->frame == NULL);
12451
12452
      /*
12453
       * This value will also be the overall result of JSON parsing
12454
       * (it's already owned by the `mjs_alt_json_parse()`)
12455
       */
12456
      ctx->result = v;
12457
    }
12458
12459
    if (token->type == JSON_TYPE_OBJECT_START ||
12460
        token->type == JSON_TYPE_ARRAY_START) {
12461
      /* New object or array has just started, so we need to allocate a frame
12462
       * for it */
12463
      struct json_parse_frame *new_frame = alloc_json_frame(ctx, v);
12464
      new_frame->up = ctx->frame;
12465
      ctx->frame = new_frame;
12466
    }
12467
  }
12468
12469
  mjs_disown(ctx->mjs, &v);
12470
}
12471
12472
MJS_PRIVATE mjs_err_t
12473
mjs_json_parse(struct mjs *mjs, const char *str, size_t len, mjs_val_t *res) {
12474
  struct json_parse_ctx *ctx =
12475
      (struct json_parse_ctx *) calloc(sizeof(struct json_parse_ctx), 1);
12476
  int json_res;
12477
  enum mjs_err rcode = MJS_OK;
12478
12479
  ctx->mjs = mjs;
12480
  ctx->result = MJS_UNDEFINED;
12481
  ctx->frame = NULL;
12482
  ctx->rcode = MJS_OK;
12483
12484
  mjs_own(mjs, &ctx->result);
12485
12486
  {
12487
    /*
12488
     * We have to reallocate the buffer before invoking json_walk, because
12489
     * frozen_cb can create new strings, which can result in the reallocation
12490
     * of mjs string mbuf, invalidating the `str` pointer.
12491
     */
12492
    char *stmp = malloc(len);
12493
    memcpy(stmp, str, len);
12494
    json_res = json_walk(stmp, len, frozen_cb, ctx);
12495
    free(stmp);
12496
    stmp = NULL;
12497
12498
    /* str might have been invalidated, so null it out */
12499
    str = NULL;
12500
  }
12501
12502
  if (ctx->rcode != MJS_OK) {
12503
    rcode = ctx->rcode;
12504
    mjs_prepend_errorf(mjs, rcode, "invalid JSON string");
12505
  } else if (json_res < 0) {
12506
    /* There was an error during parsing */
12507
    rcode = MJS_TYPE_ERROR;
12508
    mjs_prepend_errorf(mjs, rcode, "invalid JSON string");
12509
  } else {
12510
    /* Expression is parsed successfully */
12511
    *res = ctx->result;
12512
12513
    /* There should be no allocated frames */
12514
    assert(ctx->frame == NULL);
12515
  }
12516
12517
  if (rcode != MJS_OK) {
12518
    /* There might be some allocated frames in case of malformed JSON */
12519
    while (ctx->frame != NULL) {
12520
      ctx->frame = free_json_frame(ctx, ctx->frame);
12521
    }
12522
  }
12523
12524
  mjs_disown(mjs, &ctx->result);
12525
  free(ctx);
12526
12527
  return rcode;
12528
}
12529
12530
MJS_PRIVATE void mjs_op_json_stringify(struct mjs *mjs) {
12531
  mjs_val_t ret = MJS_UNDEFINED;
12532
  mjs_val_t val = mjs_arg(mjs, 0);
12533
12534
  if (mjs_nargs(mjs) < 1) {
12535
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "missing a value to stringify");
12536
  } else {
12537
    char *p = NULL;
12538
    if (mjs_json_stringify(mjs, val, NULL, 0, &p) == MJS_OK) {
12539
      ret = mjs_mk_string(mjs, p, ~0, 1 /* copy */);
12540
      free(p);
12541
    }
12542
  }
12543
12544
  mjs_return(mjs, ret);
12545
}
12546
12547
MJS_PRIVATE void mjs_op_json_parse(struct mjs *mjs) {
12548
  mjs_val_t ret = MJS_UNDEFINED;
12549
  mjs_val_t arg0 = mjs_arg(mjs, 0);
12550
12551
  if (mjs_is_string(arg0)) {
12552
    size_t len;
12553
    const char *str = mjs_get_string(mjs, &arg0, &len);
12554
    mjs_json_parse(mjs, str, len, &ret);
12555
  } else {
12556
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "string argument required");
12557
  }
12558
12559
  mjs_return(mjs, ret);
12560
}
12561
#ifdef MJS_MODULE_LINES
12562
#line 1 "mjs/src/mjs_main.c"
12563
#endif
12564
/*
12565
 * Copyright (c) 2014-2017 Cesanta Software Limited
12566
 * All rights reserved
12567
 */
12568
12569
12570
// #include <dlfcn.h>
12571
12572
/* Amalgamated: #include "mjs/src/mjs_core.h" */
12573
/* Amalgamated: #include "mjs/src/mjs_exec.h" */
12574
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
12575
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
12576
/* Amalgamated: #include "mjs/src/mjs_util.h" */
12577
12578
// added to conform afl
12579
78
char* read_input() {
12580
78
    int counter = 0;
12581
78
    char* chars = malloc(sizeof(char) * 1000);
12582
78
    char c = 0;
12583
705
    while((c = fgetc(stdin)) != EOF){
12584
549
        if (counter == 1000) {
12585
            exit(1);
12586
        }
12587
549
        chars[counter++] = c;
12588
    }
12589
78
    chars[counter] = '\0';
12590
78
    return chars;
12591
}
12592
// end adding
12593
12594
78
int main(int argc, char *argv[]) {
12595
78
  struct mjs *mjs = mjs_create();
12596
78
  mjs_val_t res = MJS_UNDEFINED;
12597
78
  mjs_err_t err = MJS_OK;
12598
  int i;
12599
12600

78
  for (i = 1; i < argc && argv[i][0] == '-' && err == MJS_OK; i++) {
12601
    if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) {
12602
      cs_log_set_level(atoi(argv[++i]));
12603
    } else if (strcmp(argv[i], "-j") == 0) {
12604
      mjs_set_generate_jsc(mjs, 1);
12605
    } else if (strcmp(argv[i], "-e") == 0 && i + 1 < argc) {
12606
      err = mjs_exec(mjs, argv[++i], &res);
12607
    } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
12608
      err = mjs_exec_file(mjs, argv[++i], &res);
12609
    } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
12610
      printf("mJS (c) Cesanta, built: " __DATE__ "\n");
12611
      printf("Usage:\n");
12612
      printf("%s [OPTIONS] [js_file ...]\n", argv[0]);
12613
      printf("OPTIONS:\n");
12614
      printf("  -e string    - Execute JavaScript expression\n");
12615
      printf("  -j           - Enable code precompiling to .jsc files\n");
12616
      printf("  -f js_file   - Execute code from .js JavaScript file\n");
12617
      printf("  -l level     - Set debug level, from 0 to 5\n");
12618
      return EXIT_SUCCESS;
12619
    } else {
12620
      fprintf(stderr, "Unknown flag: [%s]\n", argv[i]);
12621
      return EXIT_FAILURE;
12622
    }
12623
  }
12624
12625
78
  if (err != MJS_OK) {
12626
        mjs_print_error(mjs, stdout, NULL, 1 /* print_stack_trace */);
12627
        return EXIT_FAILURE;
12628
  }
12629
78
  err = mjs_exec(mjs, read_input(), &res);
12630
12631
78
  if (err == MJS_OK) {
12632
66
    mjs_fprintf(res, mjs, stdout);
12633
66
    putchar('\n');
12634
  } else {
12635
12
    mjs_print_error(mjs, stdout, NULL, 1 /* print_stack_trace */);
12636
  }
12637
78
  mjs_destroy(mjs);
12638
12639
78
  return EXIT_SUCCESS;
12640
}
12641
#ifdef MJS_MODULE_LINES
12642
#line 1 "mjs/src/mjs_object.c"
12643
#endif
12644
/*
12645
 * Copyright (c) 2016 Cesanta Software Limited
12646
 * All rights reserved
12647
 */
12648
12649
/* Amalgamated: #include "mjs/src/mjs_object.h" */
12650
/* Amalgamated: #include "mjs/src/mjs_conversion.h" */
12651
/* Amalgamated: #include "mjs/src/mjs_core.h" */
12652
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
12653
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
12654
/* Amalgamated: #include "mjs/src/mjs_string.h" */
12655
/* Amalgamated: #include "mjs/src/mjs_util.h" */
12656
12657
/* Amalgamated: #include "common/mg_str.h" */
12658
12659
235
MJS_PRIVATE mjs_val_t mjs_object_to_value(struct mjs_object *o) {
12660
235
  if (o == NULL) {
12661
    return MJS_NULL;
12662
  } else {
12663
235
    return mjs_legit_pointer_to_value(o) | MJS_TAG_OBJECT;
12664
  }
12665
}
12666
12667
3387
MJS_PRIVATE struct mjs_object *get_object_struct(mjs_val_t v) {
12668
3387
  struct mjs_object *ret = NULL;
12669
3387
  if (mjs_is_null(v)) {
12670
    ret = NULL;
12671
  } else {
12672
3387
    assert(mjs_is_object(v));
12673
3387
    ret = (struct mjs_object *) get_ptr(v);
12674
  }
12675
3387
  return ret;
12676
}
12677
12678
235
mjs_val_t mjs_mk_object(struct mjs *mjs) {
12679
235
  struct mjs_object *o = new_object(mjs);
12680
235
  if (o == NULL) {
12681
    return MJS_NULL;
12682
  }
12683
  (void) mjs;
12684
235
  o->properties = NULL;
12685
235
  return mjs_object_to_value(o);
12686
}
12687
12688
9514
int mjs_is_object(mjs_val_t v) {
12689

11986
  return (v & MJS_TAG_MASK) == MJS_TAG_OBJECT ||
12690
2472
         (v & MJS_TAG_MASK) == MJS_TAG_ARRAY;
12691
}
12692
12693
1446
MJS_PRIVATE struct mjs_property *mjs_get_own_property(struct mjs *mjs,
12694
                                                      mjs_val_t obj,
12695
                                                      const char *name,
12696
                                                      size_t len) {
12697
  struct mjs_property *p;
12698
  struct mjs_object *o;
12699
12700
1446
  if (!mjs_is_object(obj)) {
12701
    return NULL;
12702
  }
12703
12704
1446
  o = get_object_struct(obj);
12705
12706
1446
  if (len <= 5) {
12707
39
    mjs_val_t ss = mjs_mk_string(mjs, name, len, 1);
12708
624
    for (p = o->properties; p != NULL; p = p->next) {
12709
585
      if (p->name == ss) return p;
12710
    }
12711
  } else {
12712
9720
    for (p = o->properties; p != NULL; p = p->next) {
12713
8313
      if (mjs_strcmp(mjs, &p->name, name, len) == 0) return p;
12714
    }
12715
1407
    return p;
12716
  }
12717
12718
39
  return NULL;
12719
}
12720
12721
41
MJS_PRIVATE struct mjs_property *mjs_get_own_property_v(struct mjs *mjs,
12722
                                                        mjs_val_t obj,
12723
                                                        mjs_val_t key) {
12724
  size_t n;
12725
41
  char *s = NULL;
12726
41
  int need_free = 0;
12727
41
  struct mjs_property *p = NULL;
12728
41
  mjs_err_t err = mjs_to_string(mjs, &key, &s, &n, &need_free);
12729
41
  if (err == MJS_OK) {
12730
41
    p = mjs_get_own_property(mjs, obj, s, n);
12731
  }
12732
41
  if (need_free) free(s);
12733
41
  return p;
12734
}
12735
12736
1405
MJS_PRIVATE struct mjs_property *mjs_mk_property(struct mjs *mjs,
12737
                                                 mjs_val_t name,
12738
                                                 mjs_val_t value) {
12739
1405
  struct mjs_property *p = new_property(mjs);
12740
1405
  p->next = NULL;
12741
1405
  p->name = name;
12742
1405
  p->value = value;
12743
1405
  return p;
12744
}
12745
12746
mjs_val_t mjs_get(struct mjs *mjs, mjs_val_t obj, const char *name,
12747
                  size_t name_len) {
12748
  struct mjs_property *p;
12749
12750
  if (name_len == (size_t) ~0) {
12751
    name_len = strlen(name);
12752
  }
12753
12754
  p = mjs_get_own_property(mjs, obj, name, name_len);
12755
  if (p == NULL) {
12756
    return MJS_UNDEFINED;
12757
  } else {
12758
    return p->value;
12759
  }
12760
}
12761
12762
mjs_val_t mjs_get_v(struct mjs *mjs, mjs_val_t obj, mjs_val_t name) {
12763
  size_t n;
12764
  char *s = NULL;
12765
  int need_free = 0;
12766
  mjs_val_t ret = MJS_UNDEFINED;
12767
12768
  mjs_err_t err = mjs_to_string(mjs, &name, &s, &n, &need_free);
12769
12770
  if (err == MJS_OK) {
12771
    /* Successfully converted name value to string: get the property */
12772
    ret = mjs_get(mjs, obj, s, n);
12773
  }
12774
12775
  if (need_free) {
12776
    free(s);
12777
    s = NULL;
12778
  }
12779
  return ret;
12780
}
12781
12782
mjs_val_t mjs_get_v_proto(struct mjs *mjs, mjs_val_t obj, mjs_val_t key) {
12783
  struct mjs_property *p;
12784
  mjs_val_t pn = mjs_mk_string(mjs, MJS_PROTO_PROP_NAME, ~0, 1);
12785
  if ((p = mjs_get_own_property_v(mjs, obj, key)) != NULL) return p->value;
12786
  if ((p = mjs_get_own_property_v(mjs, obj, pn)) == NULL) return MJS_UNDEFINED;
12787
  return mjs_get_v_proto(mjs, p->value, key);
12788
}
12789
12790
1404
mjs_err_t mjs_set(struct mjs *mjs, mjs_val_t obj, const char *name,
12791
                  size_t name_len, mjs_val_t val) {
12792
1404
  return mjs_set_internal(mjs, obj, MJS_UNDEFINED, (char *) name, name_len,
12793
                          val);
12794
}
12795
12796
1
mjs_err_t mjs_set_v(struct mjs *mjs, mjs_val_t obj, mjs_val_t name,
12797
                    mjs_val_t val) {
12798
1
  return mjs_set_internal(mjs, obj, name, NULL, 0, val);
12799
}
12800
12801
1405
MJS_PRIVATE mjs_err_t mjs_set_internal(struct mjs *mjs, mjs_val_t obj,
12802
                                       mjs_val_t name_v, char *name,
12803
                                       size_t name_len, mjs_val_t val) {
12804
1405
  mjs_err_t rcode = MJS_OK;
12805
12806
  struct mjs_property *p;
12807
12808
1405
  int need_free = 0;
12809
12810
1405
  if (name == NULL) {
12811
    /* Pointer was not provided, so obtain one from the name_v. */
12812
1
    rcode = mjs_to_string(mjs, &name_v, &name, &name_len, &need_free);
12813
1
    if (rcode != MJS_OK) {
12814
      goto clean;
12815
    }
12816
  } else {
12817
    /*
12818
     * Pointer was provided, so we ignore name_v. Here we set it to undefined,
12819
     * and the actual value will be calculated later if needed.
12820
     */
12821
1404
    name_v = MJS_UNDEFINED;
12822
  }
12823
12824
1405
  p = mjs_get_own_property(mjs, obj, name, name_len);
12825
12826
1405
  if (p == NULL) {
12827
    struct mjs_object *o;
12828
1405
    if (!mjs_is_object(obj)) {
12829
      return MJS_REFERENCE_ERROR;
12830
    }
12831
12832
    /*
12833
     * name_v might be not a string here. In this case, we need to create a new
12834
     * `name_v`, which will be a string.
12835
     */
12836
1405
    if (!mjs_is_string(name_v)) {
12837
1404
      name_v = mjs_mk_string(mjs, name, name_len, 1);
12838
    }
12839
12840
1405
    p = mjs_mk_property(mjs, name_v, val);
12841
12842
1405
    o = get_object_struct(obj);
12843
1405
    p->next = o->properties;
12844
1405
    o->properties = p;
12845
  }
12846
12847
1405
  p->value = val;
12848
12849
clean:
12850
1405
  if (need_free) {
12851
    free(name);
12852
    name = NULL;
12853
  }
12854
1405
  return rcode;
12855
}
12856
12857
MJS_PRIVATE void mjs_destroy_property(struct mjs_property **p) {
12858
  *p = NULL;
12859
}
12860
12861
/*
12862
 * See comments in `object_public.h`
12863
 */
12864
int mjs_del(struct mjs *mjs, mjs_val_t obj, const char *name, size_t len) {
12865
  struct mjs_property *prop, *prev;
12866
12867
  if (!mjs_is_object(obj)) {
12868
    return -1;
12869
  }
12870
  if (len == (size_t) ~0) {
12871
    len = strlen(name);
12872
  }
12873
  for (prev = NULL, prop = get_object_struct(obj)->properties; prop != NULL;
12874
       prev = prop, prop = prop->next) {
12875
    size_t n;
12876
    const char *s = mjs_get_string(mjs, &prop->name, &n);
12877
    if (n == len && strncmp(s, name, len) == 0) {
12878
      if (prev) {
12879
        prev->next = prop->next;
12880
      } else {
12881
        get_object_struct(obj)->properties = prop->next;
12882
      }
12883
      mjs_destroy_property(&prop);
12884
      return 0;
12885
    }
12886
  }
12887
  return -1;
12888
}
12889
12890
mjs_val_t mjs_next(struct mjs *mjs, mjs_val_t obj, mjs_val_t *iterator) {
12891
  struct mjs_property *p = NULL;
12892
  mjs_val_t key = MJS_UNDEFINED;
12893
12894
  if (*iterator == MJS_UNDEFINED) {
12895
    struct mjs_object *o = get_object_struct(obj);
12896
    p = o->properties;
12897
  } else {
12898
    p = ((struct mjs_property *) get_ptr(*iterator))->next;
12899
  }
12900
12901
  if (p == NULL) {
12902
    *iterator = MJS_UNDEFINED;
12903
  } else {
12904
    key = p->name;
12905
    *iterator = mjs_mk_foreign(mjs, p);
12906
  }
12907
12908
  return key;
12909
}
12910
12911
MJS_PRIVATE void mjs_op_create_object(struct mjs *mjs) {
12912
  mjs_val_t ret = MJS_UNDEFINED;
12913
  mjs_val_t proto_v = mjs_arg(mjs, 0);
12914
12915
  if (!mjs_check_arg(mjs, 0, "proto", MJS_TYPE_OBJECT_GENERIC, &proto_v)) {
12916
    goto clean;
12917
  }
12918
12919
  ret = mjs_mk_object(mjs);
12920
  mjs_set(mjs, ret, MJS_PROTO_PROP_NAME, ~0, proto_v);
12921
12922
clean:
12923
  mjs_return(mjs, ret);
12924
}
12925
12926
mjs_val_t mjs_struct_to_obj(struct mjs *mjs, const void *base,
12927
                            const struct mjs_c_struct_member *def) {
12928
  mjs_val_t obj;
12929
  if (base == NULL || def == NULL) return MJS_UNDEFINED;
12930
  obj = mjs_mk_object(mjs);
12931
  mjs_own(mjs, &obj); /* Pin the object while it is being built */
12932
  for (; def->name != NULL; def++) {
12933
    const char *ptr = (const char *) base + def->offset;
12934
    switch (def->type) {
12935
      case MJS_FFI_CTYPE_INT: {
12936
        double value = (double) (*(int *) ptr);
12937
        mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, value));
12938
        break;
12939
      }
12940
      case MJS_FFI_CTYPE_CHAR_PTR: {
12941
        const char *value = *(const char **) ptr;
12942
        mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, value, ~0, 1));
12943
        break;
12944
      }
12945
      case MJS_FFI_CTYPE_DOUBLE: {
12946
        mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, *(double *) ptr));
12947
        break;
12948
      }
12949
      case MJS_FFI_CTYPE_STRUCT_MG_STR: {
12950
        const struct mg_str *s = (const struct mg_str *) ptr;
12951
        mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, s->p, s->len, 1));
12952
        break;
12953
      }
12954
      case MJS_FFI_CTYPE_STRUCT_MG_STR_PTR: {
12955
        const struct mg_str *s = *(const struct mg_str **) ptr;
12956
        mjs_set(mjs, obj, def->name, ~0, mjs_mk_string(mjs, s->p, s->len, 1));
12957
        break;
12958
      }
12959
      case MJS_FFI_CTYPE_FLOAT: {
12960
        float value = *(float *) ptr;
12961
        mjs_set(mjs, obj, def->name, ~0, mjs_mk_number(mjs, value));
12962
        break;
12963
      }
12964
      case MJS_FFI_CTYPE_VOID_PTR: {
12965
        mjs_set(mjs, obj, def->name, ~0, mjs_mk_foreign(mjs, *(void **) ptr));
12966
        break;
12967
      }
12968
      case MJS_FFI_CTYPE_BOOL: {
12969
        mjs_set(mjs, obj, def->name, ~0, mjs_mk_boolean(mjs, *(bool *) ptr));
12970
        break;
12971
      }
12972
      default:
12973
        obj = MJS_UNDEFINED;
12974
        goto clean;
12975
    }
12976
  }
12977
clean:
12978
  mjs_disown(mjs, &obj);
12979
  return obj;
12980
}
12981
#ifdef MJS_MODULE_LINES
12982
#line 1 "mjs/src/mjs_parser.c"
12983
#endif
12984
/*
12985
 * Copyright (c) 2017 Cesanta Software Limited
12986
 * All rights reserved
12987
 */
12988
12989
/* Amalgamated: #include "common/cs_varint.h" */
12990
12991
/* Amalgamated: #include "mjs/src/mjs_bcode.h" */
12992
/* Amalgamated: #include "mjs/src/mjs_core.h" */
12993
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
12994
/* Amalgamated: #include "mjs/src/mjs_parser.h" */
12995
/* Amalgamated: #include "mjs/src/mjs_string.h" */
12996
/* Amalgamated: #include "mjs/src/mjs_tok.h" */
12997
12998
#ifndef MAX_TOKS_IN_EXPR
12999
#define MAX_TOKS_IN_EXPR 40
13000
#endif
13001
13002
#define FAIL_ERR(p, code)                                                      \
13003
  do {                                                                         \
13004
    mjs_set_errorf(p->mjs, code, "parse error at line %d: [%.*s]", p->line_no, \
13005
                   10, p->tok.ptr);                                            \
13006
    mjs_print_error(p->mjs, stdout, NULL, 1 /* print_stack_trace */);             \
13007
    exit(EXIT_FAILURE);                                                        \
13008
                       /*return code;*/                                                               \
13009
  } while (0)
13010
13011
#define pnext1(p)                                    \
13012
  do {                                               \
13013
    LOG(LL_VERBOSE_DEBUG, ("  PNEXT %d", __LINE__)); \
13014
    pnext(p);                                        \
13015
  } while (0)
13016
13017
#define SYNTAX_ERROR(p) FAIL_ERR(p, MJS_SYNTAX_ERROR)
13018
#undef EXPECT
13019
#define EXPECT(p, t)       \
13020
  if ((p)->tok.tok != (t)) \
13021
    SYNTAX_ERROR(p);       \
13022
  else                     \
13023
    pnext1(p);
13024
13025
static mjs_err_t parse_statement(struct pstate *p);
13026
static mjs_err_t parse_expr(struct pstate *p);
13027
13028
79
static int ptest(struct pstate *p) {
13029
79
  struct pstate saved = *p;
13030
79
  int tok = pnext(p);
13031
79
  *p = saved;
13032
79
  return tok;
13033
}
13034
13035
static int s_unary_ops[] = {TOK_NOT, TOK_TILDA, TOK_PLUS_PLUS, TOK_MINUS_MINUS,
13036
                            TOK_KEYWORD_TYPEOF, TOK_MINUS, TOK_PLUS, TOK_EOF};
13037
static int s_comparison_ops[] = {TOK_LT, TOK_LE, TOK_GT, TOK_GE, TOK_EOF};
13038
static int s_postfix_ops[] = {TOK_PLUS_PLUS, TOK_MINUS_MINUS, TOK_EOF};
13039
static int s_equality_ops[] = {TOK_EQ, TOK_NE, TOK_EQ_EQ, TOK_NE_NE, TOK_EOF};
13040
static int s_assign_ops[] = {
13041
    TOK_ASSIGN,         TOK_PLUS_ASSIGN, TOK_MINUS_ASSIGN,  TOK_MUL_ASSIGN,
13042
    TOK_DIV_ASSIGN,     TOK_REM_ASSIGN,  TOK_LSHIFT_ASSIGN, TOK_RSHIFT_ASSIGN,
13043
    TOK_URSHIFT_ASSIGN, TOK_AND_ASSIGN,  TOK_XOR_ASSIGN,    TOK_OR_ASSIGN,
13044
    TOK_EOF};
13045
13046
2067
static int findtok(int *toks, int tok) {
13047
2067
  int i = 0;
13048

2067
  while (tok != toks[i] && toks[i] != TOK_EOF) i++;
13049
2067
  return toks[i];
13050
}
13051
13052
68
static void emit_op(struct pstate *pstate, int tok) {
13053

68
  assert(tok >= 0 && tok <= 255);
13054
68
  emit_byte(pstate, OP_EXPR);
13055
68
  emit_byte(pstate, (uint8_t) tok);
13056
68
}
13057
13058
#define BINOP_STACK_FRAME_SIZE 16
13059
#define STACK_LIMIT 8192
13060
13061
// Intentionally left as macro rather than a function, to let the
13062
// compiler to inline calls and mimimize runtime stack usage.
13063
#define PARSE_LTR_BINOP(p, f1, f2, ops, prev_op)                               \
13064
  do {                                                                         \
13065
    mjs_err_t res = MJS_OK;                                                    \
13066
    p->depth++;                                                                \
13067
    if (p->depth > (STACK_LIMIT / BINOP_STACK_FRAME_SIZE)) {                   \
13068
      mjs_set_errorf(p->mjs, MJS_SYNTAX_ERROR, "parser stack overflow");       \
13069
      res = MJS_SYNTAX_ERROR;                                                  \
13070
      goto binop_clean;                                                        \
13071
    }                                                                          \
13072
    if ((res = f1(p, TOK_EOF)) != MJS_OK) goto binop_clean;                    \
13073
    if (prev_op != TOK_EOF) emit_op(p, prev_op);                               \
13074
    if (findtok(ops, p->tok.tok) != TOK_EOF) {                                 \
13075
      int op = p->tok.tok;                                                     \
13076
      size_t off_if = 0;                                                       \
13077
      /* For AND/OR, implement short-circuit evaluation */                     \
13078
      if (ops[0] == TOK_LOGICAL_AND || ops[0] == TOK_LOGICAL_OR) {             \
13079
        emit_byte(p,                                                           \
13080
                  (uint8_t)(ops[0] == TOK_LOGICAL_AND ? OP_JMP_NEUTRAL_FALSE   \
13081
                                                      : OP_JMP_NEUTRAL_TRUE)); \
13082
        off_if = p->cur_idx;                                                   \
13083
        emit_init_offset(p);                                                   \
13084
        /* No need to emit TOK_LOGICAL_AND and TOK_LOGICAL_OR: */              \
13085
        /* Just drop the first value, and evaluate the second one. */          \
13086
        emit_byte(p, (uint8_t) OP_DROP);                                       \
13087
        op = TOK_EOF;                                                          \
13088
      }                                                                        \
13089
      pnext1(p);                                                               \
13090
      if ((res = f2(p, op)) != MJS_OK) goto binop_clean;                       \
13091
                                                                               \
13092
      if (off_if != 0) {                                                       \
13093
        mjs_bcode_insert_offset(p, p->mjs, off_if,                             \
13094
                                p->cur_idx - off_if - MJS_INIT_OFFSET_SIZE);   \
13095
      }                                                                        \
13096
    }                                                                          \
13097
  binop_clean:                                                                 \
13098
    p->depth--;                                                                \
13099
    return res;                                                                \
13100
  } while (0)
13101
13102
#define PARSE_RTL_BINOP(p, f1, f2, ops, prev_op)        \
13103
  do {                                                  \
13104
    mjs_err_t res = MJS_OK;                             \
13105
    (void) prev_op;                                     \
13106
    if ((res = f1(p, TOK_EOF)) != MJS_OK) return res;   \
13107
    if (findtok(ops, p->tok.tok) != TOK_EOF) {          \
13108
      int op = p->tok.tok;                              \
13109
      pnext1(p);                                        \
13110
      if ((res = f2(p, TOK_EOF)) != MJS_OK) return res; \
13111
      emit_op(p, op);                                   \
13112
    }                                                   \
13113
    return res;                                         \
13114
  } while (0)
13115
13116
#if MJS_INIT_OFFSET_SIZE > 0
13117
10
static void emit_init_offset(struct pstate *p) {
13118
  size_t i;
13119
20
  for (i = 0; i < MJS_INIT_OFFSET_SIZE; i++) {
13120
10
    emit_byte(p, 0);
13121
  }
13122
10
}
13123
#else
13124
static void emit_init_offset(struct pstate *p) {
13125
  (void) p;
13126
}
13127
#endif
13128
13129
83
static mjs_err_t parse_statement_list(struct pstate *p, int et) {
13130
83
  mjs_err_t res = MJS_OK;
13131
83
  int drop = 0;
13132
83
  pnext1(p);
13133

272
  while (res == MJS_OK && p->tok.tok != TOK_EOF && p->tok.tok != et) {
13134
106
    if (drop) emit_byte(p, OP_DROP);
13135
106
    res = parse_statement(p);
13136
106
    drop = 1;
13137

106
    while (p->tok.tok == TOK_SEMICOLON) pnext1(p);
13138
  }
13139
13140
  /*
13141
   * Client code expects statement list to contain a value, so if the statement
13142
   * list was empty, push `undefined`.
13143
   */
13144
83
  if (!drop) {
13145
3
    emit_byte(p, OP_PUSH_UNDEF);
13146
  }
13147
83
  return res;
13148
}
13149
13150
5
static mjs_err_t parse_block(struct pstate *p, int mkscope) {
13151
5
  mjs_err_t res = MJS_OK;
13152
5
  p->depth++;
13153
5
  if (p->depth > (STACK_LIMIT / BINOP_STACK_FRAME_SIZE)) {
13154
    mjs_set_errorf(p->mjs, MJS_SYNTAX_ERROR, "parser stack overflow");
13155
    res = MJS_SYNTAX_ERROR;
13156
    return res;
13157
  }
13158
5
  LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr));
13159
5
  if (mkscope) emit_byte(p, OP_NEW_SCOPE);
13160
5
  res = parse_statement_list(p, TOK_CLOSE_CURLY);
13161

5
  EXPECT(p, TOK_CLOSE_CURLY);
13162
5
  if (mkscope) emit_byte(p, OP_DEL_SCOPE);
13163
5
  return res;
13164
}
13165
13166
static mjs_err_t parse_function(struct pstate *p) {
13167
  size_t prologue, off;
13168
  int arg_no = 0;
13169
  int name_provided = 0;
13170
  mjs_err_t res = MJS_OK;
13171
13172
  EXPECT(p, TOK_KEYWORD_FUNCTION);
13173
13174
  if (p->tok.tok == TOK_IDENT) {
13175
    /* Function name was provided */
13176
    struct tok tmp = p->tok;
13177
    name_provided = 1;
13178
    emit_byte(p, OP_PUSH_STR);
13179
    emit_str(p, tmp.ptr, tmp.len);
13180
    emit_byte(p, OP_PUSH_SCOPE);
13181
    emit_byte(p, OP_CREATE);
13182
    emit_byte(p, OP_PUSH_STR);
13183
    emit_str(p, tmp.ptr, tmp.len);
13184
    emit_byte(p, OP_FIND_SCOPE);
13185
    pnext1(p);
13186
  }
13187
13188
  emit_byte(p, OP_JMP);
13189
  off = p->cur_idx;
13190
  emit_init_offset(p);
13191
13192
  prologue = p->cur_idx;
13193
13194
  EXPECT(p, TOK_OPEN_PAREN);
13195
  emit_byte(p, OP_NEW_SCOPE);
13196
  // Emit names of function arguments
13197
  while (p->tok.tok != TOK_CLOSE_PAREN) {
13198
    if (p->tok.tok != TOK_IDENT) SYNTAX_ERROR(p);
13199
    emit_byte(p, OP_SET_ARG);
13200
    emit_int(p, arg_no);
13201
    arg_no++;
13202
    emit_str(p, p->tok.ptr, p->tok.len);
13203
    if (ptest(p) == TOK_COMMA) pnext1(p);
13204
    pnext1(p);
13205
  }
13206
  EXPECT(p, TOK_CLOSE_PAREN);
13207
  if ((res = parse_block(p, 0)) != MJS_OK) return res;
13208
  emit_byte(p, OP_RETURN);
13209
  prologue += mjs_bcode_insert_offset(p, p->mjs, off,
13210
                                      p->cur_idx - off - MJS_INIT_OFFSET_SIZE);
13211
  emit_byte(p, OP_PUSH_FUNC);
13212
  emit_int(p, p->cur_idx - 1 /* OP_PUSH_FUNC */ - prologue);
13213
  if (name_provided) {
13214
    emit_op(p, TOK_ASSIGN);
13215
  }
13216
13217
  return res;
13218
}
13219
13220
2
static mjs_err_t parse_object_literal(struct pstate *p) {
13221
2
  mjs_err_t res = MJS_OK;
13222

2
  EXPECT(p, TOK_OPEN_CURLY);
13223
2
  emit_byte(p, OP_PUSH_OBJ);
13224
2
  while (p->tok.tok != TOK_CLOSE_CURLY) {
13225
    if (p->tok.tok != TOK_IDENT && p->tok.tok != TOK_STR) SYNTAX_ERROR(p);
13226
    emit_byte(p, OP_DUP);
13227
    emit_byte(p, OP_PUSH_STR);
13228
    emit_str(p, p->tok.ptr, p->tok.len);
13229
    emit_byte(p, OP_SWAP);
13230
    pnext1(p);
13231
    EXPECT(p, TOK_COLON);
13232
    if ((res = parse_expr(p)) != MJS_OK) return res;
13233
    emit_op(p, TOK_ASSIGN);
13234
    emit_byte(p, OP_DROP);
13235
    if (p->tok.tok == TOK_COMMA) {
13236
      pnext1(p);
13237
    } else if (p->tok.tok != TOK_CLOSE_CURLY) {
13238
      SYNTAX_ERROR(p);
13239
    }
13240
  }
13241
2
  return res;
13242
}
13243
13244
1
static mjs_err_t parse_array_literal(struct pstate *p) {
13245
1
  mjs_err_t res = MJS_OK;
13246

1
  EXPECT(p, TOK_OPEN_BRACKET);
13247
1
  emit_byte(p, OP_PUSH_ARRAY);
13248
4
  while (p->tok.tok != TOK_CLOSE_BRACKET) {
13249
2
    emit_byte(p, OP_DUP);
13250
2
    if ((res = parse_expr(p)) != MJS_OK) return res;
13251
2
    emit_byte(p, OP_APPEND);
13252

2
    if (p->tok.tok == TOK_COMMA) pnext1(p);
13253
  }
13254
1
  return res;
13255
}
13256
13257
153
static enum mjs_err parse_literal(struct pstate *p, const struct tok *t) {
13258
153
  struct mbuf *bcode_gen = &p->mjs->bcode_gen;
13259
153
  enum mjs_err res = MJS_OK;
13260
153
  int tok = t->tok;
13261
153
  LOG(LL_VERBOSE_DEBUG, ("[%.*s] %p", p->tok.len, p->tok.ptr, (void *) &t));
13262



153
  switch (t->tok) {
13263
    case TOK_KEYWORD_FALSE:
13264
2
      emit_byte(p, OP_PUSH_FALSE);
13265
2
      break;
13266
    case TOK_KEYWORD_TRUE:
13267
1
      emit_byte(p, OP_PUSH_TRUE);
13268
1
      break;
13269
    case TOK_KEYWORD_UNDEFINED:
13270
1
      emit_byte(p, OP_PUSH_UNDEF);
13271
1
      break;
13272
    case TOK_KEYWORD_NULL:
13273
2
      emit_byte(p, OP_PUSH_NULL);
13274
2
      break;
13275
    case TOK_IDENT: {
13276
74
      int prev_tok = p->prev_tok;
13277
74
      int next_tok = ptest(p);
13278
74
      emit_byte(p, OP_PUSH_STR);
13279
74
      emit_str(p, t->ptr, t->len);
13280
74
      emit_byte(p, (uint8_t)(prev_tok == TOK_DOT ? OP_SWAP : OP_FIND_SCOPE));
13281

140
      if (!findtok(s_assign_ops, next_tok) &&
13282
130
          !findtok(s_postfix_ops, next_tok) &&
13283
          /* TODO(dfrank): fix: it doesn't work for prefix ops */
13284
64
          !findtok(s_postfix_ops, prev_tok)) {
13285
63
        emit_byte(p, OP_GET);
13286
      }
13287
74
      break;
13288
    }
13289
    case TOK_NUM: {
13290
42
      double iv, d = strtod(t->ptr, NULL);
13291
42
      unsigned long uv = strtoul(t->ptr + 2, NULL, 16);
13292

42
      if (t->ptr[0] == '0' && t->ptr[1] == 'x') d = uv;
13293
42
      if (modf(d, &iv) == 0) {
13294
42
        emit_byte(p, OP_PUSH_INT);
13295
42
        emit_int(p, (int64_t) d);
13296
      } else {
13297
        emit_byte(p, OP_PUSH_DBL);
13298
        emit_str(p, t->ptr, t->len);
13299
      }
13300
42
      break;
13301
    }
13302
    case TOK_STR: {
13303
      size_t oldlen;
13304
25
      emit_byte(p, OP_PUSH_STR);
13305
25
      oldlen = bcode_gen->len;
13306
25
      embed_string(bcode_gen, p->cur_idx, t->ptr, t->len, EMBSTR_UNESCAPE);
13307
25
      p->cur_idx += bcode_gen->len - oldlen;
13308
25
    } break;
13309
    case TOK_OPEN_BRACKET:
13310
1
      res = parse_array_literal(p);
13311
1
      break;
13312
    case TOK_OPEN_CURLY:
13313
2
      res = parse_object_literal(p);
13314
2
      break;
13315
    case TOK_OPEN_PAREN:
13316
2
      pnext1(p);
13317
2
      res = parse_expr(p);
13318
2
      if (p->tok.tok != TOK_CLOSE_PAREN) SYNTAX_ERROR(p);
13319
2
      break;
13320
    case TOK_KEYWORD_FUNCTION:
13321
      res = parse_function(p);
13322
      break;
13323
    case TOK_KEYWORD_THIS:
13324
1
      emit_byte(p, OP_PUSH_THIS);
13325
1
      break;
13326
    default:
13327
      SYNTAX_ERROR(p);
13328
  }
13329

153
  if (tok != TOK_KEYWORD_FUNCTION) pnext1(p);
13330
153
  return res;
13331
}
13332
13333
153
static mjs_err_t parse_call_dot_mem(struct pstate *p, int prev_op) {
13334
153
  int ops[] = {TOK_DOT, TOK_OPEN_PAREN, TOK_OPEN_BRACKET, TOK_EOF};
13335
153
  mjs_err_t res = MJS_OK;
13336
153
  if ((res = parse_literal(p, &p->tok)) != MJS_OK) return res;
13337
309
  while (findtok(ops, p->tok.tok) != TOK_EOF) {
13338
3
    if (p->tok.tok == TOK_OPEN_BRACKET) {
13339
1
      int prev_tok = p->prev_tok;
13340

1
      EXPECT(p, TOK_OPEN_BRACKET);
13341
1
      if ((res = parse_expr(p)) != MJS_OK) return res;
13342
1
      emit_byte(p, OP_SWAP);
13343

1
      EXPECT(p, TOK_CLOSE_BRACKET);
13344

2
      if (!findtok(s_assign_ops, p->tok.tok) &&
13345
2
          !findtok(s_postfix_ops, p->tok.tok) &&
13346
          /* TODO(dfrank): fix: it doesn't work for prefix ops */
13347
1
          !findtok(s_postfix_ops, prev_tok)) {
13348
1
        emit_byte(p, OP_GET);
13349
      }
13350
2
    } else if (p->tok.tok == TOK_OPEN_PAREN) {
13351

1
      EXPECT(p, TOK_OPEN_PAREN);
13352
1
      emit_byte(p, OP_ARGS);
13353
4
      while (p->tok.tok != TOK_CLOSE_PAREN) {
13354
2
        if ((res = parse_expr(p)) != MJS_OK) return res;
13355

2
        if (p->tok.tok == TOK_COMMA) pnext1(p);
13356
      }
13357
1
      emit_byte(p, OP_CALL);
13358

1
      EXPECT(p, TOK_CLOSE_PAREN);
13359
1
    } else if (p->tok.tok == TOK_DOT) {
13360

1
      EXPECT(p, TOK_DOT);
13361
1
      if ((res = parse_call_dot_mem(p, TOK_DOT)) != MJS_OK) return res;
13362
    }
13363
  }
13364
  (void) prev_op;
13365
153
  return res;
13366
}
13367
13368
152
static mjs_err_t parse_postfix(struct pstate *p, int prev_op) {
13369
152
  mjs_err_t res = MJS_OK;
13370
152
  if ((res = parse_call_dot_mem(p, prev_op)) != MJS_OK) return res;
13371

152
  if (p->tok.tok == TOK_PLUS_PLUS || p->tok.tok == TOK_MINUS_MINUS) {
13372
3
    int op = p->tok.tok == TOK_PLUS_PLUS ? TOK_POSTFIX_PLUS : TOK_POSTFIX_MINUS;
13373
3
    emit_op(p, op);
13374
3
    pnext1(p);
13375
  }
13376
152
  return res;
13377
}
13378
13379
154
static mjs_err_t parse_unary(struct pstate *p, int prev_op) {
13380
154
  mjs_err_t res = MJS_OK;
13381
154
  int op = TOK_EOF;
13382
154
  if (findtok(s_unary_ops, p->tok.tok) != TOK_EOF) {
13383
16
    op = p->tok.tok;
13384
16
    pnext1(p);
13385
  }
13386
154
  if (findtok(s_unary_ops, p->tok.tok) != TOK_EOF) {
13387
2
    res = parse_unary(p, prev_op);
13388
  } else {
13389
152
    res = parse_postfix(p, prev_op);
13390
  }
13391
154
  if (res != MJS_OK) return res;
13392
154
  if (op != TOK_EOF) {
13393
16
    if (op == TOK_MINUS) op = TOK_UNARY_MINUS;
13394
16
    if (op == TOK_PLUS) op = TOK_UNARY_PLUS;
13395
16
    emit_op(p, op);
13396
  }
13397
154
  return res;
13398
}
13399
13400
152
static mjs_err_t parse_mul_div_rem(struct pstate *p, int prev_op) {
13401
152
  int ops[] = {TOK_MUL, TOK_DIV, TOK_REM, TOK_EOF};
13402





152
  PARSE_LTR_BINOP(p, parse_unary, parse_mul_div_rem, ops, prev_op);
13403
}
13404
13405
141
static mjs_err_t parse_plus_minus(struct pstate *p, int prev_op) {
13406
141
  int ops[] = {TOK_PLUS, TOK_MINUS, TOK_EOF};
13407





141
  PARSE_LTR_BINOP(p, parse_mul_div_rem, parse_plus_minus, ops, prev_op);
13408
}
13409
13410
137
static mjs_err_t parse_shifts(struct pstate *p, int prev_op) {
13411
137
  int ops[] = {TOK_LSHIFT, TOK_RSHIFT, TOK_URSHIFT, TOK_EOF};
13412





137
  PARSE_LTR_BINOP(p, parse_plus_minus, parse_shifts, ops, prev_op);
13413
}
13414
13415
135
static mjs_err_t parse_comparison(struct pstate *p, int prev_op) {
13416





135
  PARSE_LTR_BINOP(p, parse_shifts, parse_comparison, s_comparison_ops, prev_op);
13417
}
13418
13419
129
static mjs_err_t parse_equality(struct pstate *p, int prev_op) {
13420





129
  PARSE_LTR_BINOP(p, parse_comparison, parse_equality, s_equality_ops, prev_op);
13421
}
13422
13423
127
static mjs_err_t parse_bitwise_and(struct pstate *p, int prev_op) {
13424
127
  int ops[] = {TOK_AND, TOK_EOF};
13425





127
  PARSE_LTR_BINOP(p, parse_equality, parse_bitwise_and, ops, prev_op);
13426
}
13427
13428
123
static mjs_err_t parse_bitwise_xor(struct pstate *p, int prev_op) {
13429
123
  int ops[] = {TOK_XOR, TOK_EOF};
13430





123
  PARSE_LTR_BINOP(p, parse_bitwise_and, parse_bitwise_xor, ops, prev_op);
13431
}
13432
13433
119
static mjs_err_t parse_bitwise_or(struct pstate *p, int prev_op) {
13434
119
  int ops[] = {TOK_OR, TOK_EOF};
13435





119
  PARSE_LTR_BINOP(p, parse_bitwise_xor, parse_bitwise_or, ops, prev_op);
13436
}
13437
13438
113
static mjs_err_t parse_logical_and(struct pstate *p, int prev_op) {
13439
113
  int ops[] = {TOK_LOGICAL_AND, TOK_EOF};
13440





113
  PARSE_LTR_BINOP(p, parse_bitwise_or, parse_logical_and, ops, prev_op);
13441
}
13442
13443
112
static mjs_err_t parse_logical_or(struct pstate *p, int prev_op) {
13444
112
  int ops[] = {TOK_LOGICAL_OR, TOK_EOF};
13445





112
  PARSE_LTR_BINOP(p, parse_logical_and, parse_logical_or, ops, prev_op);
13446
}
13447
13448
112
static mjs_err_t parse_ternary(struct pstate *p, int prev_op) {
13449
112
  mjs_err_t res = MJS_OK;
13450
112
  if ((res = parse_logical_or(p, TOK_EOF)) != MJS_OK) return res;
13451
112
  if (prev_op != TOK_EOF) emit_op(p, prev_op);
13452
13453
112
  if (p->tok.tok == TOK_QUESTION) {
13454
    size_t off_if, off_endif, off_else;
13455

2
    EXPECT(p, TOK_QUESTION);
13456
13457
2
    emit_byte(p, OP_JMP_FALSE);
13458
2
    off_if = p->cur_idx;
13459
2
    emit_init_offset(p);
13460
13461
2
    if ((res = parse_ternary(p, TOK_EOF)) != MJS_OK) return res;
13462
13463
2
    emit_byte(p, OP_JMP);
13464
2
    off_else = p->cur_idx;
13465
2
    emit_init_offset(p);
13466
2
    off_endif = p->cur_idx;
13467
13468
2
    emit_byte(p, OP_DROP);
13469
13470

2
    EXPECT(p, TOK_COLON);
13471
2
    if ((res = parse_ternary(p, TOK_EOF)) != MJS_OK) return res;
13472
13473
    /*
13474
     * NOTE: if inserting offset causes the code to move, off_endif needs to be
13475
     * adjusted
13476
     */
13477
2
    off_endif += mjs_bcode_insert_offset(
13478
2
        p, p->mjs, off_else, p->cur_idx - off_else - MJS_INIT_OFFSET_SIZE);
13479
13480
2
    mjs_bcode_insert_offset(p, p->mjs, off_if,
13481
2
                            off_endif - off_if - MJS_INIT_OFFSET_SIZE);
13482
  }
13483
13484
112
  return res;
13485
}
13486
13487
108
static mjs_err_t parse_assignment(struct pstate *p, int prev_op) {
13488


108
  PARSE_RTL_BINOP(p, parse_ternary, parse_assignment, s_assign_ops, prev_op);
13489
}
13490
13491
98
static mjs_err_t parse_expr(struct pstate *p) {
13492
98
  return parse_assignment(p, TOK_EOF);
13493
}
13494
13495
1
static mjs_err_t parse_let(struct pstate *p) {
13496
1
  mjs_err_t res = MJS_OK;
13497
1
  LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr));
13498

1
  EXPECT(p, TOK_KEYWORD_LET);
13499
  for (;;) {
13500
1
    struct tok tmp = p->tok;
13501

1
    EXPECT(p, TOK_IDENT);
13502
13503
1
    emit_byte(p, OP_PUSH_STR);
13504
1
    emit_str(p, tmp.ptr, tmp.len);
13505
1
    emit_byte(p, OP_PUSH_SCOPE);
13506
1
    emit_byte(p, OP_CREATE);
13507
13508
1
    if (p->tok.tok == TOK_ASSIGN) {
13509
      pnext1(p);
13510
      emit_byte(p, OP_PUSH_STR);
13511
      emit_str(p, tmp.ptr, tmp.len);
13512
      emit_byte(p, OP_FIND_SCOPE);
13513
      if ((res = parse_expr(p)) != MJS_OK) return res;
13514
      emit_op(p, TOK_ASSIGN);
13515
    } else {
13516
1
      emit_byte(p, OP_PUSH_UNDEF);
13517
    }
13518
1
    if (p->tok.tok == TOK_COMMA) {
13519
      emit_byte(p, OP_DROP);
13520
      pnext1(p);
13521
    }
13522

1
    if (p->tok.tok == TOK_SEMICOLON || p->tok.tok == TOK_EOF) break;
13523
  }
13524
1
  return res;
13525
}
13526
13527
5
static mjs_err_t parse_block_or_stmt(struct pstate *p, int cs) {
13528
5
  if (ptest(p) == TOK_OPEN_CURLY) {
13529
1
    return parse_block(p, cs);
13530
  } else {
13531
4
    return parse_statement(p);
13532
  }
13533
}
13534
13535
static mjs_err_t parse_for_in(struct pstate *p) {
13536
  mjs_err_t res = MJS_OK;
13537
  size_t off_b, off_check_end;
13538
13539
  /* new scope should be pushed before OP_LOOP instruction */
13540
  emit_byte(p, OP_NEW_SCOPE);
13541
13542
  /* Put iterator variable name to the stack */
13543
  if (p->tok.tok == TOK_KEYWORD_LET) {
13544
    EXPECT(p, TOK_KEYWORD_LET);
13545
    emit_byte(p, OP_PUSH_STR);
13546
    emit_str(p, p->tok.ptr, p->tok.len);
13547
    emit_byte(p, OP_PUSH_SCOPE);
13548
    emit_byte(p, OP_CREATE);
13549
  }
13550
  emit_byte(p, OP_PUSH_STR);
13551
  emit_str(p, p->tok.ptr, p->tok.len);
13552
13553
  /* Put object to the stack */
13554
  EXPECT(p, TOK_IDENT);
13555
  EXPECT(p, TOK_KEYWORD_IN);
13556
  parse_expr(p);
13557
  EXPECT(p, TOK_CLOSE_PAREN);
13558
13559
  emit_byte(p, OP_PUSH_UNDEF); /* Push iterator */
13560
13561
  /* Before parsing condition statement, push break/continue offsets  */
13562
  emit_byte(p, OP_LOOP);
13563
  off_b = p->cur_idx;
13564
  emit_init_offset(p);
13565
  emit_byte(p, 0); /* Point OP_CONTINUE to the next instruction */
13566
13567
  emit_byte(p, OP_FOR_IN_NEXT);
13568
  emit_byte(p, OP_DUP);
13569
  emit_byte(p, OP_JMP_FALSE);
13570
  off_check_end = p->cur_idx;
13571
  emit_init_offset(p);
13572
13573
  // Parse loop body
13574
  if (p->tok.tok == TOK_OPEN_CURLY) {
13575
    if ((res = parse_statement_list(p, TOK_CLOSE_CURLY)) != MJS_OK) return res;
13576
    pnext1(p);
13577
  } else {
13578
    if ((res = parse_statement(p)) != MJS_OK) return res;
13579
  }
13580
  emit_byte(p, OP_DROP);
13581
  emit_byte(p, OP_CONTINUE);
13582
13583
  /* jump cond -> break */
13584
  mjs_bcode_insert_offset(p, p->mjs, off_check_end,
13585
                          p->cur_idx - off_check_end - MJS_INIT_OFFSET_SIZE);
13586
13587
  /* NOTE: jump C -> cond link is already established, it's constant: zero */
13588
13589
  emit_byte(p, OP_BREAK);
13590
13591
  /* jump B -> cond */
13592
  mjs_bcode_insert_offset(p, p->mjs, off_b,
13593
                          p->cur_idx - off_b - MJS_INIT_OFFSET_SIZE);
13594
13595
  emit_byte(p, OP_DROP);
13596
  emit_byte(p, OP_DROP);
13597
  emit_byte(p, OP_DROP);
13598
  emit_byte(p, OP_DEL_SCOPE);
13599
13600
  return res;
13601
}
13602
13603
static int check_for_in(struct pstate *p) {
13604
  struct pstate saved = *p;
13605
  int forin = 0;
13606
  if (p->tok.tok == TOK_KEYWORD_LET) pnext1(p);
13607
  if (p->tok.tok == TOK_IDENT) {
13608
    pnext1(p);
13609
    if (p->tok.tok == TOK_KEYWORD_IN) forin = 1;
13610
  }
13611
  *p = saved;
13612
  return forin;
13613
}
13614
13615
static mjs_err_t parse_for(struct pstate *p) {
13616
  mjs_err_t res = MJS_OK;
13617
  size_t off_b, off_c, off_init_end;
13618
  size_t off_incr_begin, off_cond_begin, off_cond_end;
13619
  int buf_cur_idx;
13620
13621
  LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr));
13622
  EXPECT(p, TOK_KEYWORD_FOR);
13623
  EXPECT(p, TOK_OPEN_PAREN);
13624
13625
  /* Look forward - is it for..in ? */
13626
  if (check_for_in(p)) return parse_for_in(p);
13627
13628
  /*
13629
   * BC is a break+continue offsets (a part of OP_LOOP opcode)
13630
   *
13631
   *  BC init  incr  cond  body  break  del_scope
13632
   *  ||    |  ^     ^  |        ^      ^
13633
   *  ||    +--|-----+  |        |      |
13634
   *  |+-------+        +--------+      |
13635
   *  +---------------------------------+
13636
   *
13637
   * The order to setup links:
13638
   *
13639
   *   cond -> break
13640
   *   init -> cond
13641
   *   C -> incr
13642
   *   B -> del_scope
13643
   */
13644
13645
  /* new scope should be pushed before OP_LOOP instruction */
13646
  emit_byte(p, OP_NEW_SCOPE);
13647
13648
  /* Before parsing condition statement, push break/continue offsets  */
13649
  emit_byte(p, OP_LOOP);
13650
  off_b = p->cur_idx;
13651
  emit_init_offset(p);
13652
  off_c = p->cur_idx;
13653
  emit_init_offset(p);
13654
13655
  /* Parse init statement */
13656
  if (p->tok.tok == TOK_KEYWORD_LET) {
13657
    if ((res = parse_let(p)) != MJS_OK) return res;
13658
  } else {
13659
    if ((res = parse_expr(p)) != MJS_OK) return res;
13660
  }
13661
  EXPECT(p, TOK_SEMICOLON);
13662
  emit_byte(p, OP_DROP);
13663
13664
  emit_byte(p, OP_JMP);
13665
  off_init_end = p->cur_idx;
13666
  emit_init_offset(p);
13667
13668
  off_incr_begin = p->cur_idx;
13669
  off_cond_begin = p->cur_idx;
13670
13671
  /* Parse cond statement */
13672
  if ((res = parse_expr(p)) != MJS_OK) return res;
13673
  EXPECT(p, TOK_SEMICOLON);
13674
13675
  /* Parse incr statement */
13676
  /* Incr statement should be placed before cond, so, adjust cur_idx */
13677
  buf_cur_idx = p->cur_idx;
13678
  p->cur_idx = off_incr_begin;
13679
13680
  if ((res = parse_expr(p)) != MJS_OK) return res;
13681
  EXPECT(p, TOK_CLOSE_PAREN);
13682
  emit_byte(p, OP_DROP);
13683
13684
  /*
13685
   * Now incr is inserted before cond, so we adjust cur_idx back, and set
13686
   * off_cond_begin to the correct value
13687
   */
13688
  {
13689
    int incr_size = p->cur_idx - off_incr_begin;
13690
    off_cond_begin += incr_size;
13691
    p->cur_idx = buf_cur_idx + incr_size;
13692
  }
13693
13694
  /* p->cur_idx is now at the end of "cond" */
13695
  /* Exit the loop if false */
13696
  emit_byte(p, OP_JMP_FALSE);
13697
  off_cond_end = p->cur_idx;
13698
  emit_init_offset(p);
13699
13700
  /* Parse loop body */
13701
  if (p->tok.tok == TOK_OPEN_CURLY) {
13702
    if ((res = parse_statement_list(p, TOK_CLOSE_CURLY)) != MJS_OK) return res;
13703
    pnext1(p);
13704
  } else {
13705
    if ((res = parse_statement(p)) != MJS_OK) return res;
13706
  }
13707
  emit_byte(p, OP_DROP);
13708
  emit_byte(p, OP_CONTINUE);
13709
13710
  /* p->cur_idx is at the "break" item now */
13711
13712
  /* jump cond -> break */
13713
  mjs_bcode_insert_offset(p, p->mjs, off_cond_end,
13714
                          p->cur_idx - off_cond_end - MJS_INIT_OFFSET_SIZE);
13715
13716
  /* jump init -> cond (and adjust off_incr_begin which may move) */
13717
  off_incr_begin += mjs_bcode_insert_offset(
13718
      p, p->mjs, off_init_end,
13719
      off_cond_begin - off_init_end - MJS_INIT_OFFSET_SIZE);
13720
13721
  /* jump C -> incr */
13722
  mjs_bcode_insert_offset(p, p->mjs, off_c,
13723
                          off_incr_begin - off_c - MJS_INIT_OFFSET_SIZE);
13724
13725
  emit_byte(p, OP_BREAK);
13726
13727
  /* jump B -> del_scope */
13728
  mjs_bcode_insert_offset(p, p->mjs, off_b,
13729
                          p->cur_idx - off_b - MJS_INIT_OFFSET_SIZE);
13730
13731
  emit_byte(p, OP_DEL_SCOPE);
13732
13733
  return res;
13734
}
13735
13736
static mjs_err_t parse_while(struct pstate *p) {
13737
  size_t off_cond_end, off_b;
13738
  mjs_err_t res = MJS_OK;
13739
13740
  EXPECT(p, TOK_KEYWORD_WHILE);
13741
  EXPECT(p, TOK_OPEN_PAREN);
13742
13743
  /* new scope should be pushed before OP_LOOP instruction */
13744
  emit_byte(p, OP_NEW_SCOPE);
13745
13746
  /*
13747
   * BC is a break+continue offsets (a part of OP_LOOP opcode)
13748
   *
13749
   *   BC cond body break del_scope
13750
   *   || ^  |      ^     ^
13751
   *   || |  |      |     |
13752
   *   |+-+  +------+     |
13753
   *   +------------------+
13754
   *
13755
   * The order to setup links:
13756
   *
13757
   *    cond -> break
13758
   *    C -> cond
13759
   *    B -> del_scope
13760
   */
13761
13762
  emit_byte(p, OP_LOOP);
13763
  off_b = p->cur_idx;
13764
  emit_init_offset(p);
13765
  emit_byte(p, 0); /* Point OP_CONTINUE to the next instruction */
13766
13767
  // parse condition statement
13768
  if ((res = parse_expr(p)) != MJS_OK) return res;
13769
  EXPECT(p, TOK_CLOSE_PAREN);
13770
13771
  // Exit the loop if false
13772
  emit_byte(p, OP_JMP_FALSE);
13773
  off_cond_end = p->cur_idx;
13774
  emit_init_offset(p);
13775
13776
  // Parse loop body
13777
  if (p->tok.tok == TOK_OPEN_CURLY) {
13778
    if ((res = parse_statement_list(p, TOK_CLOSE_CURLY)) != MJS_OK) return res;
13779
    pnext1(p);
13780
  } else {
13781
    if ((res = parse_statement(p)) != MJS_OK) return res;
13782
  }
13783
  emit_byte(p, OP_DROP);
13784
  emit_byte(p, OP_CONTINUE);
13785
13786
  /* jump cond -> break */
13787
  mjs_bcode_insert_offset(p, p->mjs, off_cond_end,
13788
                          p->cur_idx - off_cond_end - MJS_INIT_OFFSET_SIZE);
13789
13790
  /* NOTE: jump C -> cond link is already established, it's constant: zero */
13791
13792
  emit_byte(p, OP_BREAK);
13793
13794
  /* jump B -> cond */
13795
  mjs_bcode_insert_offset(p, p->mjs, off_b,
13796
                          p->cur_idx - off_b - MJS_INIT_OFFSET_SIZE);
13797
13798
  emit_byte(p, OP_DEL_SCOPE);
13799
  return res;
13800
}
13801
13802
5
static mjs_err_t parse_if(struct pstate *p) {
13803
  size_t off_if, off_endif;
13804
5
  mjs_err_t res = MJS_OK;
13805
5
  LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr));
13806

5
  EXPECT(p, TOK_KEYWORD_IF);
13807

5
  EXPECT(p, TOK_OPEN_PAREN);
13808
5
  if ((res = parse_expr(p)) != MJS_OK) return res;
13809
13810
5
  emit_byte(p, OP_JMP_FALSE);
13811
5
  off_if = p->cur_idx;
13812
5
  emit_init_offset(p);
13813
13814

5
  EXPECT(p, TOK_CLOSE_PAREN);
13815
5
  if ((res = parse_block_or_stmt(p, 1)) != MJS_OK) return res;
13816
13817
5
  if (p->tok.tok == TOK_KEYWORD_ELSE) {
13818
    /*
13819
     * Else clause is present, so, if the condition is not true, the jump
13820
     * target (off_endif) should be not the current offset, but the offset
13821
     * after jump-over-else opcode
13822
     */
13823
    size_t off_else, off_endelse;
13824
    pnext1(p);
13825
    emit_byte(p, OP_JMP);
13826
    off_else = p->cur_idx;
13827
    emit_init_offset(p);
13828
    off_endif = p->cur_idx;
13829
13830
    emit_byte(p, OP_DROP);
13831
    if ((res = parse_block_or_stmt(p, 1)) != MJS_OK) return res;
13832
    off_endelse = p->cur_idx;
13833
13834
    /*
13835
     * NOTE: if inserting offset causes the code to move, off_endif needs to be
13836
     * adjusted
13837
     */
13838
    off_endif += mjs_bcode_insert_offset(
13839
        p, p->mjs, off_else, off_endelse - off_else - MJS_INIT_OFFSET_SIZE);
13840
  } else {
13841
    /* Else clause is not present, so, current offset is a jump target
13842
     * (off_endif) */
13843
5
    off_endif = p->cur_idx;
13844
  }
13845
13846
5
  mjs_bcode_insert_offset(p, p->mjs, off_if,
13847
5
                          off_endif - off_if - MJS_INIT_OFFSET_SIZE);
13848
13849
5
  return res;
13850
}
13851
13852
static void pstate_revert(struct pstate *p, struct pstate *old,
13853
                          int old_bcode_gen_len) {
13854
  p->pos = old->pos;
13855
  p->line_no = old->line_no;
13856
  p->last_emitted_line_no = old->last_emitted_line_no;
13857
  p->offset_lineno_map.len = old->offset_lineno_map.len;
13858
  p->prev_tok = old->prev_tok;
13859
  p->tok = old->tok;
13860
  p->mjs->bcode_gen.len = old_bcode_gen_len;
13861
  p->cur_idx = old->cur_idx;
13862
  p->depth = old->depth;
13863
}
13864
13865
2
static mjs_err_t parse_return(struct pstate *p) {
13866
  int old_bcode_gen_len;
13867
  struct pstate p_saved;
13868

2
  EXPECT(p, TOK_KEYWORD_RETURN);
13869
2
  p_saved = *p;
13870
2
  old_bcode_gen_len = p->mjs->bcode_gen.len;
13871
2
  if (parse_expr(p) != MJS_OK) {
13872
    /*
13873
     * Failed to parse an expression to return, so return the parser to the
13874
     * prior state and push undefined.
13875
     */
13876
    pstate_revert(p, &p_saved, old_bcode_gen_len);
13877
    emit_byte(p, OP_PUSH_UNDEF);
13878
  }
13879
2
  emit_byte(p, OP_SETRETVAL);
13880
2
  emit_byte(p, OP_RETURN);
13881
2
  return MJS_OK;
13882
}
13883
13884
110
static mjs_err_t parse_statement(struct pstate *p) {
13885
110
  LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr));
13886


110
  switch (p->tok.tok) {
13887
    case TOK_SEMICOLON:
13888
1
      emit_byte(p, OP_PUSH_UNDEF);
13889
1
      pnext1(p);
13890
1
      return MJS_OK;
13891
    case TOK_KEYWORD_LET:
13892
1
      return parse_let(p);
13893
    case TOK_OPEN_CURLY:
13894
4
      return parse_block(p, 1);
13895
    case TOK_KEYWORD_RETURN:
13896
2
      return parse_return(p);
13897
    case TOK_KEYWORD_FOR:
13898
      return parse_for(p);
13899
    case TOK_KEYWORD_WHILE:
13900
      return parse_while(p);
13901
    case TOK_KEYWORD_BREAK:
13902
1
      emit_byte(p, OP_PUSH_UNDEF);
13903
1
      emit_byte(p, OP_BREAK);
13904
1
      pnext1(p);
13905
1
      return MJS_OK;
13906
    case TOK_KEYWORD_CONTINUE:
13907
1
      emit_byte(p, OP_CONTINUE);
13908
1
      pnext1(p);
13909
1
      return MJS_OK;
13910
    case TOK_KEYWORD_IF:
13911
5
      return parse_if(p);
13912
    case TOK_KEYWORD_CASE:
13913
    case TOK_KEYWORD_CATCH:
13914
    case TOK_KEYWORD_DELETE:
13915
    case TOK_KEYWORD_DO:
13916
    case TOK_KEYWORD_INSTANCEOF:
13917
    case TOK_KEYWORD_NEW:
13918
    case TOK_KEYWORD_SWITCH:
13919
    case TOK_KEYWORD_THROW:
13920
    case TOK_KEYWORD_TRY:
13921
    case TOK_KEYWORD_VAR:
13922
    case TOK_KEYWORD_VOID:
13923
    case TOK_KEYWORD_WITH:
13924
12
      mjs_set_errorf(p->mjs, MJS_SYNTAX_ERROR, "[%.*s] is not implemented",
13925
                     p->tok.len, p->tok.ptr);
13926
12
      return MJS_SYNTAX_ERROR;
13927
    default: {
13928
83
      mjs_err_t res = MJS_OK;
13929
      for (;;) {
13930
84
        if ((res = parse_expr(p)) != MJS_OK) return res;
13931
84
        if (p->tok.tok != TOK_COMMA) break;
13932
1
        emit_byte(p, OP_DROP);
13933
1
        pnext1(p);
13934
1
      }
13935
83
      return res;
13936
    }
13937
  }
13938
}
13939
13940
MJS_PRIVATE mjs_err_t
13941
78
mjs_parse(const char *path, const char *buf, struct mjs *mjs) {
13942
78
  mjs_err_t res = MJS_OK;
13943
  struct pstate p;
13944
  size_t start_idx, llen;
13945
  int map_len;
13946
  mjs_header_item_t bcode_offset, map_offset, total_size;
13947
13948
78
  pinit(path, buf, &p);
13949
78
  p.mjs = mjs;
13950
78
  p.cur_idx = p.mjs->bcode_gen.len;
13951
78
  emit_byte(&p, OP_BCODE_HEADER);
13952
13953
  /*
13954
   * TODO(dfrank): don't access mjs->bcode_gen directly, use emit_... API which
13955
   * takes care of p->cur_idx
13956
   */
13957
13958
  /* Remember starting bcode position, and reserve the room for bcode header */
13959
78
  start_idx = p.mjs->bcode_gen.len;
13960
78
  mbuf_append(&p.mjs->bcode_gen, NULL,
13961
              sizeof(mjs_header_item_t) * MJS_HDR_ITEMS_CNT);
13962
13963
  /* Append NULL-terminated filename */
13964
78
  mbuf_append(&p.mjs->bcode_gen, path, strlen(path) + 1 /* null-terminate */);
13965
13966
78
  bcode_offset = p.mjs->bcode_gen.len - start_idx;
13967
78
  memcpy(p.mjs->bcode_gen.buf + start_idx +
13968
             sizeof(mjs_header_item_t) * MJS_HDR_ITEM_BCODE_OFFSET,
13969
         &bcode_offset, sizeof(mjs_header_item_t));
13970
13971
78
  p.start_bcode_idx = p.mjs->bcode_gen.len;
13972
78
  p.cur_idx = p.mjs->bcode_gen.len;
13973
13974
78
  res = parse_statement_list(&p, TOK_EOF);
13975
78
  emit_byte(&p, OP_EXIT);
13976
13977
  /* remember map offset */
13978
78
  map_offset = p.mjs->bcode_gen.len - start_idx;
13979
78
  memcpy(p.mjs->bcode_gen.buf + start_idx +
13980
             sizeof(mjs_header_item_t) * MJS_HDR_ITEM_MAP_OFFSET,
13981
         &map_offset, sizeof(mjs_header_item_t));
13982
13983
  /* put map length varint */
13984
78
  map_len = p.offset_lineno_map.len;
13985
78
  llen = cs_varint_llen(map_len);
13986
78
  mbuf_resize(&p.mjs->bcode_gen, p.mjs->bcode_gen.size + llen);
13987
78
  cs_varint_encode(
13988
78
      map_len, (uint8_t *) p.mjs->bcode_gen.buf + p.mjs->bcode_gen.len, llen);
13989
78
  p.mjs->bcode_gen.len += llen;
13990
13991
  /* put the map itself */
13992
78
  mbuf_append(&p.mjs->bcode_gen, p.offset_lineno_map.buf,
13993
              p.offset_lineno_map.len);
13994
13995
78
  total_size = p.mjs->bcode_gen.len - start_idx;
13996
78
  memcpy(p.mjs->bcode_gen.buf + start_idx +
13997
             sizeof(mjs_header_item_t) * MJS_HDR_ITEM_TOTAL_SIZE,
13998
         &total_size, sizeof(mjs_header_item_t));
13999
14000
78
  mbuf_free(&p.offset_lineno_map);
14001
14002
  /*
14003
   * If parsing was successful, commit the bcode; otherwise drop generated
14004
   * bcode
14005
   */
14006
78
  if (res == MJS_OK) {
14007
66
    mjs_bcode_commit(mjs);
14008
  } else {
14009
12
    mbuf_free(&mjs->bcode_gen);
14010
  }
14011
14012
78
  return res;
14013
}
14014
#ifdef MJS_MODULE_LINES
14015
#line 1 "mjs/src/mjs_primitive.c"
14016
#endif
14017
/*
14018
 * Copyright (c) 2017 Cesanta Software Limited
14019
 * All rights reserved
14020
 */
14021
14022
/* Amalgamated: #include "mjs/src/mjs_core.h" */
14023
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
14024
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
14025
14026
2
mjs_val_t mjs_mk_null(void) {
14027
2
  return MJS_NULL;
14028
}
14029
14030
3443
int mjs_is_null(mjs_val_t v) {
14031
3443
  return v == MJS_NULL;
14032
}
14033
14034
5
mjs_val_t mjs_mk_undefined(void) {
14035
5
  return MJS_UNDEFINED;
14036
}
14037
14038
55
int mjs_is_undefined(mjs_val_t v) {
14039
55
  return v == MJS_UNDEFINED;
14040
}
14041
14042
37
mjs_val_t mjs_mk_number(struct mjs *mjs, double v) {
14043
  mjs_val_t res;
14044
  (void) mjs;
14045
  /* not every NaN is a JS NaN */
14046
37
  if (isnan(v)) {
14047
    res = MJS_TAG_NAN;
14048
  } else {
14049
    union {
14050
      double d;
14051
      mjs_val_t r;
14052
    } u;
14053
37
    u.d = v;
14054
37
    res = u.r;
14055
  }
14056
37
  return res;
14057
}
14058
14059
105
static double get_double(mjs_val_t v) {
14060
  union {
14061
    double d;
14062
    mjs_val_t v;
14063
  } u;
14064
105
  u.v = v;
14065
  /* Due to NaN packing, any non-numeric value is already a valid NaN value */
14066
105
  return u.d;
14067
}
14068
14069
15
double mjs_get_double(struct mjs *mjs, mjs_val_t v) {
14070
  (void) mjs;
14071
15
  return get_double(v);
14072
}
14073
14074
int mjs_get_int(struct mjs *mjs, mjs_val_t v) {
14075
  (void) mjs;
14076
  /*
14077
   * NOTE(dfrank): without double cast, all numbers >= 0x80000000 are always
14078
   * converted to exactly 0x80000000.
14079
   */
14080
  return (int) (unsigned int) get_double(v);
14081
}
14082
14083
int32_t mjs_get_int32(struct mjs *mjs, mjs_val_t v) {
14084
  (void) mjs;
14085
  return (int32_t) get_double(v);
14086
}
14087
14088
90
int mjs_is_number(mjs_val_t v) {
14089

90
  return v == MJS_TAG_NAN || !isnan(get_double(v));
14090
}
14091
14092
3
mjs_val_t mjs_mk_boolean(struct mjs *mjs, int v) {
14093
  (void) mjs;
14094
3
  return (v ? 1 : 0) | MJS_TAG_BOOLEAN;
14095
}
14096
14097
2
int mjs_get_bool(struct mjs *mjs, mjs_val_t v) {
14098
  (void) mjs;
14099
2
  if (mjs_is_boolean(v)) {
14100
2
    return v & 1;
14101
  } else {
14102
    return 0;
14103
  }
14104
}
14105
14106
65
int mjs_is_boolean(mjs_val_t v) {
14107
65
  return (v & MJS_TAG_MASK) == MJS_TAG_BOOLEAN;
14108
}
14109
14110
#define MJS_IS_POINTER_LEGIT(n) \
14111
  (((n) &MJS_TAG_MASK) == 0 || ((n) &MJS_TAG_MASK) == (~0 & MJS_TAG_MASK))
14112
14113
1092
MJS_PRIVATE mjs_val_t mjs_pointer_to_value(struct mjs *mjs, void *p) {
14114
1092
  uint64_t n = ((uint64_t)(uintptr_t) p);
14115
14116

1092
  if (!MJS_IS_POINTER_LEGIT(n)) {
14117
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "invalid pointer value: %p", p);
14118
  }
14119
1092
  return n & ~MJS_TAG_MASK;
14120
}
14121
14122
235
MJS_PRIVATE mjs_val_t mjs_legit_pointer_to_value(void *p) {
14123
235
  uint64_t n = ((uint64_t)(uintptr_t) p);
14124
14125

235
  assert(MJS_IS_POINTER_LEGIT(n));
14126
235
  return n & ~MJS_TAG_MASK;
14127
}
14128
14129
6538
MJS_PRIVATE void *get_ptr(mjs_val_t v) {
14130
6538
  return (void *) (uintptr_t)(v & 0xFFFFFFFFFFFFUL);
14131
}
14132
14133
void *mjs_get_ptr(struct mjs *mjs, mjs_val_t v) {
14134
  (void) mjs;
14135
  if (!mjs_is_foreign(v)) {
14136
    return NULL;
14137
  }
14138
  return get_ptr(v);
14139
}
14140
14141
mjs_val_t mjs_mk_foreign(struct mjs *mjs, void *p) {
14142
  (void) mjs;
14143
  return mjs_pointer_to_value(mjs, p) | MJS_TAG_FOREIGN;
14144
}
14145
14146
1092
mjs_val_t mjs_mk_foreign_func(struct mjs *mjs, mjs_func_ptr_t fn) {
14147
  union {
14148
    mjs_func_ptr_t fn;
14149
    void *p;
14150
  } u;
14151
1092
  u.fn = fn;
14152
  (void) mjs;
14153
1092
  return mjs_pointer_to_value(mjs, u.p) | MJS_TAG_FOREIGN;
14154
}
14155
14156
83
int mjs_is_foreign(mjs_val_t v) {
14157
83
  return (v & MJS_TAG_MASK) == MJS_TAG_FOREIGN;
14158
}
14159
14160
mjs_val_t mjs_mk_function(struct mjs *mjs, size_t off) {
14161
  (void) mjs;
14162
  return (mjs_val_t) off | MJS_TAG_FUNCTION;
14163
}
14164
14165
56
int mjs_is_function(mjs_val_t v) {
14166
56
  return (v & MJS_TAG_MASK) == MJS_TAG_FUNCTION;
14167
}
14168
14169
MJS_PRIVATE void mjs_op_isnan(struct mjs *mjs) {
14170
  mjs_val_t ret = MJS_UNDEFINED;
14171
  mjs_val_t val = mjs_arg(mjs, 0);
14172
14173
  ret = mjs_mk_boolean(mjs, val == MJS_TAG_NAN);
14174
14175
  mjs_return(mjs, ret);
14176
}
14177
#ifdef MJS_MODULE_LINES
14178
#line 1 "mjs/src/mjs_string.c"
14179
#endif
14180
/*
14181
 * Copyright (c) 2017 Cesanta Software Limited
14182
 * All rights reserved
14183
 */
14184
14185
/* Amalgamated: #include "mjs/src/mjs_string.h" */
14186
/* Amalgamated: #include "common/cs_varint.h" */
14187
/* Amalgamated: #include "common/mg_str.h" */
14188
/* Amalgamated: #include "mjs/src/mjs_conversion.h" */
14189
/* Amalgamated: #include "mjs/src/mjs_core.h" */
14190
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
14191
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
14192
/* Amalgamated: #include "mjs/src/mjs_util.h" */
14193
14194
// No UTF
14195
typedef unsigned short Rune;
14196
28
static int chartorune(Rune *rune, const char *str) {
14197
28
  *rune = *(unsigned char *) str;
14198
28
  return 1;
14199
}
14200
28
static int runetochar(char *str, Rune *rune) {
14201
28
  str[0] = (char) *rune;
14202
28
  return 1;
14203
}
14204
14205
#ifndef MJS_STRING_BUF_RESERVE
14206
#define MJS_STRING_BUF_RESERVE 100
14207
#endif
14208
14209
MJS_PRIVATE size_t unescape(const char *s, size_t len, char *to);
14210
14211
MJS_PRIVATE void embed_string(struct mbuf *m, size_t offset, const char *p,
14212
                              size_t len, uint8_t /*enum embstr_flags*/ flags);
14213
14214
/* TODO(lsm): NaN payload location depends on endianness, make crossplatform */
14215
#define GET_VAL_NAN_PAYLOAD(v) ((char *) &(v))
14216
14217
9912
int mjs_is_string(mjs_val_t v) {
14218
9912
  uint64_t t = v & MJS_TAG_MASK;
14219

15782
  return t == MJS_TAG_STRING_I || t == MJS_TAG_STRING_F ||
14220

13029
         t == MJS_TAG_STRING_O || t == MJS_TAG_STRING_5 ||
14221
         t == MJS_TAG_STRING_D;
14222
}
14223
14224
1494
mjs_val_t mjs_mk_string(struct mjs *mjs, const char *p, size_t len, int copy) {
14225
  struct mbuf *m;
14226
1494
  mjs_val_t offset, tag = MJS_TAG_STRING_F;
14227
1494
  if (len == 0) {
14228
    /*
14229
     * Zero length for foreign string has a special meaning (that the foreign
14230
     * string is not inlined into mjs_val_t), so when creating a zero-length
14231
     * string, we always assume it'll be owned. Since the length is zero, it
14232
     * doesn't matter anyway.
14233
     */
14234
4
    copy = 1;
14235
  }
14236
1494
  m = copy ? &mjs->owned_strings : &mjs->foreign_strings;
14237
1494
  offset = m->len;
14238
14239
1494
  if (len == ~((size_t) 0)) len = strlen(p);
14240
14241
1494
  if (copy) {
14242
    /* owned string */
14243
1494
    if (len <= 4) {
14244
706
      char *s = GET_VAL_NAN_PAYLOAD(offset) + 1;
14245
706
      offset = 0;
14246
706
      if (p != 0) {
14247
706
        memcpy(s, p, len);
14248
      }
14249
706
      s[-1] = len;
14250
706
      tag = MJS_TAG_STRING_I;
14251
788
    } else if (len == 5) {
14252
316
      char *s = GET_VAL_NAN_PAYLOAD(offset);
14253
316
      offset = 0;
14254
316
      if (p != 0) {
14255
316
        memcpy(s, p, len);
14256
      }
14257
316
      tag = MJS_TAG_STRING_5;
14258
      // } else if ((dict_index = v_find_string_in_dictionary(p, len)) >= 0) {
14259
      //   offset = 0;
14260
      //   GET_VAL_NAN_PAYLOAD(offset)[0] = dict_index;
14261
      //   tag = MJS_TAG_STRING_D;
14262
    } else {
14263
472
      if (gc_strings_is_gc_needed(mjs)) {
14264
78
        mjs->need_gc = 1;
14265
      }
14266
14267
      /*
14268
       * Before embedding new string, check if the reallocation is needed.  If
14269
       * so, perform the reallocation by calling `mbuf_resize` manually, since
14270
       * we need to preallocate some extra space (`MJS_STRING_BUF_RESERVE`)
14271
       */
14272
472
      if ((m->len + len) > m->size) {
14273
78
        char *prev_buf = m->buf;
14274
78
        mbuf_resize(m, m->len + len + MJS_STRING_BUF_RESERVE);
14275
14276
        /*
14277
         * There is a corner case: when the source pointer is located within
14278
         * the mbuf. In this case, we should adjust the pointer, because it
14279
         * might have just been reallocated.
14280
         */
14281

78
        if (p >= prev_buf && p < (prev_buf + m->len)) {
14282
          p += (m->buf - prev_buf);
14283
        }
14284
      }
14285
14286
472
      embed_string(m, m->len, p, len, EMBSTR_ZERO_TERM);
14287
472
      tag = MJS_TAG_STRING_O;
14288
    }
14289
  } else {
14290
    /* foreign string */
14291
    if (sizeof(void *) <= 4 && len <= (1 << 15)) {
14292
      /* small foreign strings can fit length and ptr in the mjs_val_t */
14293
      offset = (uint64_t) len << 32 | (uint64_t)(uintptr_t) p;
14294
    } else {
14295
      /* bigger strings need indirection that uses ram */
14296
      size_t pos = m->len;
14297
      size_t llen = cs_varint_llen(len);
14298
14299
      /* allocate space for len and ptr */
14300
      mbuf_insert(m, pos, NULL, llen + sizeof(p));
14301
14302
      cs_varint_encode(len, (uint8_t *) (m->buf + pos), llen);
14303
      memcpy(m->buf + pos + llen, &p, sizeof(p));
14304
    }
14305
    tag = MJS_TAG_STRING_F;
14306
  }
14307
14308
  /* NOTE(lsm): don't use pointer_to_value, 32-bit ptrs will truncate */
14309
1494
  return (offset & ~MJS_TAG_MASK) | tag;
14310
}
14311
14312
/* Get a pointer to string and string length. */
14313
8400
const char *mjs_get_string(struct mjs *mjs, mjs_val_t *v, size_t *sizep) {
14314
8400
  uint64_t tag = v[0] & MJS_TAG_MASK;
14315
8400
  const char *p = NULL;
14316
8400
  size_t size = 0, llen;
14317
14318
8400
  if (!mjs_is_string(*v)) {
14319
    goto clean;
14320
  }
14321
14322
8400
  if (tag == MJS_TAG_STRING_I) {
14323
4000
    p = GET_VAL_NAN_PAYLOAD(*v) + 1;
14324
4000
    size = p[-1];
14325
4400
  } else if (tag == MJS_TAG_STRING_5) {
14326
1651
    p = GET_VAL_NAN_PAYLOAD(*v);
14327
1651
    size = 5;
14328
    // } else if (tag == MJS_TAG_STRING_D) {
14329
    //   int index = ((unsigned char *) GET_VAL_NAN_PAYLOAD(*v))[0];
14330
    //   size = v_dictionary_strings[index].len;
14331
    //   p = v_dictionary_strings[index].p;
14332
2749
  } else if (tag == MJS_TAG_STRING_O) {
14333
2749
    size_t offset = (size_t) gc_string_mjs_val_to_offset(*v);
14334
2749
    char *s = mjs->owned_strings.buf + offset;
14335
2749
    uint64_t v = 0;
14336

5498
    if (offset < mjs->owned_strings.len &&
14337
2749
        cs_varint_decode((uint8_t *) s, mjs->owned_strings.len - offset, &v,
14338
                         &llen)) {
14339
2749
      size = v;
14340
2749
      p = s + llen;
14341
    } else {
14342
      goto clean;
14343
    }
14344
  } else if (tag == MJS_TAG_STRING_F) {
14345
    /*
14346
     * short foreign strings on <=32-bit machines can be encoded in a compact
14347
     * form:
14348
     *
14349
     *     7         6        5        4        3        2        1        0
14350
     *  11111111|1111tttt|llllllll|llllllll|ssssssss|ssssssss|ssssssss|ssssssss
14351
     *
14352
     * Strings longer than 2^26 will be indireceted through the foreign_strings
14353
     * mbuf.
14354
     *
14355
     * We don't use a different tag to represent those two cases. Instead, all
14356
     * foreign strings represented with the help of the foreign_strings mbuf
14357
     * will have the upper 16-bits of the payload set to zero. This allows us to
14358
     * represent up to 477 million foreign strings longer than 64k.
14359
     */
14360
    uint16_t len = (*v >> 32) & 0xFFFF;
14361
    if (sizeof(void *) <= 4 && len != 0) {
14362
      size = (size_t) len;
14363
      p = (const char *) (uintptr_t) *v;
14364
    } else {
14365
      size_t offset = (size_t) gc_string_mjs_val_to_offset(*v);
14366
      char *s = mjs->foreign_strings.buf + offset;
14367
      uint64_t v = 0;
14368
      if (offset < mjs->foreign_strings.len &&
14369
          cs_varint_decode((uint8_t *) s, mjs->foreign_strings.len - offset, &v,
14370
                           &llen)) {
14371
        size = v;
14372
        memcpy((char **) &p, s + llen, sizeof(p));
14373
      } else {
14374
        goto clean;
14375
      }
14376
    }
14377
  } else {
14378
    assert(0);
14379
  }
14380
14381
clean:
14382
8400
  if (sizep != NULL) {
14383
8400
    *sizep = size;
14384
  }
14385
8400
  return p;
14386
}
14387
14388
40
const char *mjs_get_cstring(struct mjs *mjs, mjs_val_t *value) {
14389
  size_t size;
14390
40
  const char *s = mjs_get_string(mjs, value, &size);
14391
40
  if (s == NULL) return NULL;
14392

40
  if (s[size] != 0 || strlen(s) != size) {
14393
    return NULL;
14394
  }
14395
40
  return s;
14396
}
14397
14398
8313
int mjs_strcmp(struct mjs *mjs, mjs_val_t *a, const char *b, size_t len) {
14399
  size_t n;
14400
  const char *s;
14401
8313
  if (len == (size_t) ~0) len = strlen(b);
14402
8313
  s = mjs_get_string(mjs, a, &n);
14403
8313
  if (n != len) {
14404
6981
    return n - len;
14405
  }
14406
1332
  return strncmp(s, b, len);
14407
}
14408
14409
MJS_PRIVATE unsigned long cstr_to_ulong(const char *s, size_t len, int *ok) {
14410
  char *e;
14411
  unsigned long res = strtoul(s, &e, 10);
14412
  *ok = (e == s + len) && len != 0;
14413
  return res;
14414
}
14415
14416
MJS_PRIVATE mjs_err_t
14417
str_to_ulong(struct mjs *mjs, mjs_val_t v, int *ok, unsigned long *res) {
14418
  enum mjs_err ret = MJS_OK;
14419
  size_t len = 0;
14420
  const char *p = mjs_get_string(mjs, &v, &len);
14421
  *res = cstr_to_ulong(p, len, ok);
14422
14423
  return ret;
14424
}
14425
14426
MJS_PRIVATE int s_cmp(struct mjs *mjs, mjs_val_t a, mjs_val_t b) {
14427
  size_t a_len, b_len;
14428
  const char *a_ptr, *b_ptr;
14429
14430
  a_ptr = mjs_get_string(mjs, &a, &a_len);
14431
  b_ptr = mjs_get_string(mjs, &b, &b_len);
14432
14433
  if (a_len == b_len) {
14434
    return memcmp(a_ptr, b_ptr, a_len);
14435
  }
14436
  if (a_len > b_len) {
14437
    return 1;
14438
  } else if (a_len < b_len) {
14439
    return -1;
14440
  } else {
14441
    return 0;
14442
  }
14443
}
14444
14445
MJS_PRIVATE mjs_val_t s_concat(struct mjs *mjs, mjs_val_t a, mjs_val_t b) {
14446
  size_t a_len, b_len, res_len;
14447
  const char *a_ptr, *b_ptr, *res_ptr;
14448
  mjs_val_t res;
14449
14450
  /* Find out lengths of both srtings */
14451
  a_ptr = mjs_get_string(mjs, &a, &a_len);
14452
  b_ptr = mjs_get_string(mjs, &b, &b_len);
14453
14454
  /* Create a placeholder string */
14455
  res = mjs_mk_string(mjs, NULL, a_len + b_len, 1);
14456
14457
  /* mjs_mk_string() may have reallocated mbuf - revalidate pointers */
14458
  a_ptr = mjs_get_string(mjs, &a, &a_len);
14459
  b_ptr = mjs_get_string(mjs, &b, &b_len);
14460
14461
  /* Copy strings into the placeholder */
14462
  res_ptr = mjs_get_string(mjs, &res, &res_len);
14463
  memcpy((char *) res_ptr, a_ptr, a_len);
14464
  memcpy((char *) res_ptr + a_len, b_ptr, b_len);
14465
14466
  return res;
14467
}
14468
14469
MJS_PRIVATE void mjs_string_slice(struct mjs *mjs) {
14470
  int nargs = mjs_nargs(mjs);
14471
  mjs_val_t ret = mjs_mk_number(mjs, 0);
14472
  mjs_val_t beginSlice_v = MJS_UNDEFINED;
14473
  mjs_val_t endSlice_v = MJS_UNDEFINED;
14474
  int beginSlice = 0;
14475
  int endSlice = 0;
14476
  size_t size;
14477
  const char *s = NULL;
14478
14479
  /* get string from `this` */
14480
  if (!mjs_check_arg(mjs, -1 /*this*/, "this", MJS_TYPE_STRING, NULL)) {
14481
    goto clean;
14482
  }
14483
  s = mjs_get_string(mjs, &mjs->vals.this_obj, &size);
14484
14485
  /* get idx from arg 0 */
14486
  if (!mjs_check_arg(mjs, 0, "beginSlice", MJS_TYPE_NUMBER, &beginSlice_v)) {
14487
    goto clean;
14488
  }
14489
  beginSlice = mjs_normalize_idx(mjs_get_int(mjs, beginSlice_v), size);
14490
14491
  if (nargs >= 2) {
14492
    /* endSlice is given; use it */
14493
    /* get idx from arg 0 */
14494
    if (!mjs_check_arg(mjs, 1, "endSlice", MJS_TYPE_NUMBER, &endSlice_v)) {
14495
      goto clean;
14496
    }
14497
    endSlice = mjs_normalize_idx(mjs_get_int(mjs, endSlice_v), size);
14498
  } else {
14499
    /* endSlice is not given; assume the end of the string */
14500
    endSlice = size;
14501
  }
14502
14503
  if (endSlice < beginSlice) {
14504
    endSlice = beginSlice;
14505
  }
14506
14507
  ret = mjs_mk_string(mjs, s + beginSlice, endSlice - beginSlice, 1);
14508
14509
clean:
14510
  mjs_return(mjs, ret);
14511
}
14512
14513
MJS_PRIVATE void mjs_string_index_of(struct mjs *mjs) {
14514
  mjs_val_t ret = mjs_mk_number(mjs, -1);
14515
  mjs_val_t substr_v = MJS_UNDEFINED;
14516
  mjs_val_t idx_v = MJS_UNDEFINED;
14517
  int idx = 0;
14518
  const char *str = NULL, *substr = NULL;
14519
  size_t str_len = 0, substr_len = 0;
14520
14521
  if (!mjs_check_arg(mjs, -1 /* this */, "this", MJS_TYPE_STRING, NULL)) {
14522
    goto clean;
14523
  }
14524
  str = mjs_get_string(mjs, &mjs->vals.this_obj, &str_len);
14525
14526
  if (!mjs_check_arg(mjs, 0, "searchValue", MJS_TYPE_STRING, &substr_v)) {
14527
    goto clean;
14528
  }
14529
  substr = mjs_get_string(mjs, &substr_v, &substr_len);
14530
  if (mjs_nargs(mjs) > 1) {
14531
    if (!mjs_check_arg(mjs, 1, "fromIndex", MJS_TYPE_NUMBER, &idx_v)) {
14532
      goto clean;
14533
    }
14534
    idx = mjs_get_int(mjs, idx_v);
14535
    if (idx < 0) idx = 0;
14536
    if ((size_t) idx > str_len) idx = str_len;
14537
  }
14538
  {
14539
    const char *substr_p;
14540
    struct mg_str mgstr, mgsubstr;
14541
    mgstr.p = str + idx;
14542
    mgstr.len = str_len - idx;
14543
    mgsubstr.p = substr;
14544
    mgsubstr.len = substr_len;
14545
    substr_p = mg_strstr(mgstr, mgsubstr);
14546
    if (substr_p != NULL) {
14547
      ret = mjs_mk_number(mjs, (int) (substr_p - str));
14548
    }
14549
  }
14550
14551
clean:
14552
  mjs_return(mjs, ret);
14553
}
14554
14555
MJS_PRIVATE void mjs_string_char_code_at(struct mjs *mjs) {
14556
  mjs_val_t ret = MJS_UNDEFINED;
14557
  mjs_val_t idx_v = MJS_UNDEFINED;
14558
  int idx = 0;
14559
  size_t size;
14560
  const char *s = NULL;
14561
14562
  /* get string from `this` */
14563
  if (!mjs_check_arg(mjs, -1 /*this*/, "this", MJS_TYPE_STRING, NULL)) {
14564
    goto clean;
14565
  }
14566
  s = mjs_get_string(mjs, &mjs->vals.this_obj, &size);
14567
14568
  /* get idx from arg 0 */
14569
  if (!mjs_check_arg(mjs, 0, "index", MJS_TYPE_NUMBER, &idx_v)) {
14570
    goto clean;
14571
  }
14572
  idx = mjs_normalize_idx(mjs_get_int(mjs, idx_v), size);
14573
  if (idx >= 0 && idx < (int) size) {
14574
    ret = mjs_mk_number(mjs, ((unsigned char *) s)[idx]);
14575
  }
14576
14577
clean:
14578
  mjs_return(mjs, ret);
14579
}
14580
14581
MJS_PRIVATE void mjs_mkstr(struct mjs *mjs) {
14582
  int nargs = mjs_nargs(mjs);
14583
  mjs_val_t ret = MJS_UNDEFINED;
14584
14585
  char *ptr = NULL;
14586
  int offset = 0;
14587
  int len = 0;
14588
  int copy = 0;
14589
14590
  mjs_val_t ptr_v = MJS_UNDEFINED;
14591
  mjs_val_t offset_v = MJS_UNDEFINED;
14592
  mjs_val_t len_v = MJS_UNDEFINED;
14593
  mjs_val_t copy_v = MJS_UNDEFINED;
14594
14595
  if (nargs == 2) {
14596
    ptr_v = mjs_arg(mjs, 0);
14597
    len_v = mjs_arg(mjs, 1);
14598
  } else if (nargs == 3) {
14599
    ptr_v = mjs_arg(mjs, 0);
14600
    offset_v = mjs_arg(mjs, 1);
14601
    len_v = mjs_arg(mjs, 2);
14602
  } else if (nargs == 4) {
14603
    ptr_v = mjs_arg(mjs, 0);
14604
    offset_v = mjs_arg(mjs, 1);
14605
    len_v = mjs_arg(mjs, 2);
14606
    copy_v = mjs_arg(mjs, 3);
14607
  } else {
14608
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR,
14609
                       "mkstr takes 2, 3 or 4 arguments: (ptr, len), (ptr, "
14610
                       "offset, len) or (ptr, offset, len, copy)");
14611
    goto clean;
14612
  }
14613
14614
  if (!mjs_is_foreign(ptr_v)) {
14615
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "ptr should be a foreign pointer");
14616
    goto clean;
14617
  }
14618
14619
  if (offset_v != MJS_UNDEFINED && !mjs_is_number(offset_v)) {
14620
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "offset should be a number");
14621
    goto clean;
14622
  }
14623
14624
  if (!mjs_is_number(len_v)) {
14625
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "len should be a number");
14626
    goto clean;
14627
  }
14628
14629
  copy = mjs_is_truthy(mjs, copy_v);
14630
14631
  /* all arguments are fine */
14632
14633
  ptr = (char *) mjs_get_ptr(mjs, ptr_v);
14634
  if (offset_v != MJS_UNDEFINED) {
14635
    offset = mjs_get_int(mjs, offset_v);
14636
  }
14637
  len = mjs_get_int(mjs, len_v);
14638
14639
  ret = mjs_mk_string(mjs, ptr + offset, len, copy);
14640
14641
clean:
14642
  mjs_return(mjs, ret);
14643
}
14644
14645
enum unescape_error {
14646
  SLRE_INVALID_HEX_DIGIT,
14647
  SLRE_INVALID_ESC_CHAR,
14648
  SLRE_UNTERM_ESC_SEQ,
14649
};
14650
14651
static int hex(int c) {
14652
  if (c >= '0' && c <= '9') return c - '0';
14653
  if (c >= 'a' && c <= 'f') return c - 'a' + 10;
14654
  if (c >= 'A' && c <= 'F') return c - 'A' + 10;
14655
  return -SLRE_INVALID_HEX_DIGIT;
14656
}
14657
14658
10
static int nextesc(const char **p) {
14659
10
  const unsigned char *s = (unsigned char *) (*p)++;
14660



10
  switch (*s) {
14661
    case 0:
14662
      return -SLRE_UNTERM_ESC_SEQ;
14663
    case 'c':
14664
      ++*p;
14665
      return *s & 31;
14666
    case 'b':
14667
      return '\b';
14668
    case 't':
14669
      return '\t';
14670
    case 'n':
14671
      return '\n';
14672
    case 'v':
14673
      return '\v';
14674
    case 'f':
14675
2
      return '\f';
14676
    case 'r':
14677
      return '\r';
14678
    case '\\':
14679
4
      return '\\';
14680
    case 'u':
14681


2
      if (isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) &&
14682
          isxdigit(s[4])) {
14683
        (*p) += 4;
14684
        return hex(s[1]) << 12 | hex(s[2]) << 8 | hex(s[3]) << 4 | hex(s[4]);
14685
      }
14686
2
      return -SLRE_INVALID_HEX_DIGIT;
14687
    case 'x':
14688
      if (isxdigit(s[1]) && isxdigit(s[2])) {
14689
        (*p) += 2;
14690
        return (hex(s[1]) << 4) | hex(s[2]);
14691
      }
14692
      return -SLRE_INVALID_HEX_DIGIT;
14693
    default:
14694
2
      return -SLRE_INVALID_ESC_CHAR;
14695
  }
14696
}
14697
14698
50
MJS_PRIVATE size_t unescape(const char *s, size_t len, char *to) {
14699
50
  const char *end = s + len;
14700
50
  size_t n = 0;
14701
  char tmp[4];
14702
  Rune r;
14703
14704
126
  while (s < end) {
14705
26
    s += chartorune(&r, s);
14706

26
    if (r == '\\' && s < end) {
14707

16
      switch (*s) {
14708
        case '"':
14709
4
          s++, r = '"';
14710
4
          break;
14711
        case '\'':
14712
          s++, r = '\'';
14713
          break;
14714
        case '\n':
14715
2
          s++, r = '\n';
14716
2
          break;
14717
        default: {
14718
10
          const char *tmp_s = s;
14719
10
          int i = nextesc(&s);
14720
10
          switch (i) {
14721
            case -SLRE_INVALID_ESC_CHAR:
14722
2
              r = '\\';
14723
2
              s = tmp_s;
14724
2
              n += runetochar(to == NULL ? tmp : to + n, &r);
14725
2
              s += chartorune(&r, s);
14726
2
              break;
14727
            case -SLRE_INVALID_HEX_DIGIT:
14728
            default:
14729
8
              r = i;
14730
          }
14731
        }
14732
      }
14733
    }
14734
26
    n += runetochar(to == NULL ? tmp : to + n, &r);
14735
  }
14736
14737
50
  return n;
14738
}
14739
14740
497
MJS_PRIVATE void embed_string(struct mbuf *m, size_t offset, const char *p,
14741
                              size_t len, uint8_t /*enum embstr_flags*/ flags) {
14742
497
  char *old_base = m->buf;
14743

497
  uint8_t p_backed_by_mbuf = p >= old_base && p < old_base + m->len;
14744
497
  size_t n = (flags & EMBSTR_UNESCAPE) ? unescape(p, len, NULL) : len;
14745
14746
  /* Calculate how many bytes length takes */
14747
497
  size_t k = cs_varint_llen(n);
14748
14749
  /* total length: varing length + string len + zero-term */
14750
497
  size_t tot_len = k + n + !!(flags & EMBSTR_ZERO_TERM);
14751
14752
  /* Allocate buffer */
14753
497
  mbuf_insert(m, offset, NULL, tot_len);
14754
14755
  /* Fixup p if it was relocated by mbuf_insert() above */
14756
497
  if (p_backed_by_mbuf) {
14757
    p += m->buf - old_base;
14758
  }
14759
14760
  /* Write length */
14761
497
  cs_varint_encode(n, (unsigned char *) m->buf + offset, k);
14762
14763
  /* Write string */
14764
497
  if (p != 0) {
14765
497
    if (flags & EMBSTR_UNESCAPE) {
14766
25
      unescape(p, len, m->buf + offset + k);
14767
    } else {
14768
472
      memcpy(m->buf + offset + k, p, len);
14769
    }
14770
  }
14771
14772
  /* add NULL-terminator if needed */
14773
497
  if (flags & EMBSTR_ZERO_TERM) {
14774
472
    m->buf[offset + tot_len - 1] = '\0';
14775
  }
14776
497
}
14777
#ifdef MJS_MODULE_LINES
14778
#line 1 "mjs/src/mjs_tok.c"
14779
#endif
14780
/*
14781
 * Copyright (c) 2017 Cesanta Software Limited
14782
 * All rights reserved
14783
 */
14784
14785
#include <stdlib.h>
14786
#include <string.h>
14787
14788
/* Amalgamated: #include "common/cs_dbg.h" */
14789
/* Amalgamated: #include "mjs/src/mjs_tok.h" */
14790
14791
78
MJS_PRIVATE void pinit(const char *file_name, const char *buf,
14792
                       struct pstate *p) {
14793
78
  memset(p, 0, sizeof(*p));
14794
78
  p->line_no = 1;
14795
78
  p->last_emitted_line_no = 1;
14796
78
  p->file_name = file_name;
14797
78
  p->buf = p->pos = buf;
14798
78
  mbuf_init(&p->offset_lineno_map, 0);
14799
78
}
14800
14801
// We're not relying on the target libc ctype, as it may incorrectly
14802
// handle negative arguments, e.g. isspace(-1).
14803
513
static int mjs_is_space(int c) {
14804



513
  return c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '\f' || c == '\v';
14805
}
14806
14807
543
MJS_PRIVATE int mjs_is_digit(int c) {
14808

543
  return c >= '0' && c <= '9';
14809
}
14810
14811
792
static int mjs_is_alpha(int c) {
14812


792
  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
14813
}
14814
14815
731
MJS_PRIVATE int mjs_is_ident(int c) {
14816

731
  return c == '_' || c == '$' || mjs_is_alpha(c);
14817
}
14818
14819
// Try to parse a token that can take one or two chars.
14820
464
static int longtok(struct pstate *p, const char *first_chars,
14821
                   const char *second_chars) {
14822
464
  if (strchr(first_chars, p->pos[0]) == NULL) return TOK_EOF;
14823

94
  if (p->pos[1] != '\0' && strchr(second_chars, p->pos[1]) != NULL) {
14824
33
    p->tok.len++;
14825
33
    p->pos++;
14826
33
    return p->pos[-1] << 8 | p->pos[0];
14827
  }
14828
61
  return p->pos[0];
14829
}
14830
14831
// Try to parse a token that takes exactly 3 chars.
14832
478
static int longtok3(struct pstate *p, char a, char b, char c) {
14833

478
  if (p->pos[0] == a && p->pos[1] == b && p->pos[2] == c) {
14834
3
    p->tok.len += 2;
14835
3
    p->pos += 2;
14836
3
    return p->pos[-2] << 16 | p->pos[-1] << 8 | p->pos[0];
14837
  }
14838
475
  return TOK_EOF;
14839
}
14840
14841
// Try to parse a token that takes exactly 4 chars.
14842
95
static int longtok4(struct pstate *p, char a, char b, char c, char d) {
14843


95
  if (p->pos[0] == a && p->pos[1] == b && p->pos[2] == c && p->pos[3] == d) {
14844
    p->tok.len += 3;
14845
    p->pos += 3;
14846
    return p->pos[-3] << 24 | p->pos[-2] << 16 | p->pos[-1] << 8 | p->pos[0];
14847
  }
14848
95
  return TOK_EOF;
14849
}
14850
14851
42
static int getnum(struct pstate *p) {
14852

42
  if (p->pos[0] == '0' && p->pos[1] == 'x') {
14853
    // MSVC6 strtod cannot parse 0x... numbers, thus this ugly workaround.
14854
1
    strtoul(p->pos + 2, (char **) &p->pos, 16);
14855
  } else {
14856
41
    strtod(p->pos, (char **) &p->pos);
14857
  }
14858
42
  p->tok.len = p->pos - p->tok.ptr;
14859
42
  p->pos--;
14860
42
  return TOK_NUM;
14861
}
14862
14863
107
static int is_reserved_word_token(const char *s, int len) {
14864
107
  const char *reserved[] = {
14865
      "break",     "case",   "catch", "continue",   "debugger", "default",
14866
      "delete",    "do",     "else",  "false",      "finally",  "for",
14867
      "function",  "if",     "in",    "instanceof", "new",      "null",
14868
      "return",    "switch", "this",  "throw",      "true",     "try",
14869
      "typeof",    "var",    "void",  "while",      "with",     "let",
14870
      "undefined", NULL};
14871
  int i;
14872
107
  if (!mjs_is_alpha(s[0])) return 0;
14873
2356
  for (i = 0; reserved[i] != NULL; i++) {
14874

2298
    if (len == (int) strlen(reserved[i]) && strncmp(s, reserved[i], len) == 0)
14875
30
      return i + 1;
14876
  }
14877
58
  return 0;
14878
}
14879
14880
107
static int getident(struct pstate *p) {
14881

107
  while (mjs_is_ident(p->pos[0]) || mjs_is_digit(p->pos[0])) p->pos++;
14882
107
  p->tok.len = p->pos - p->tok.ptr;
14883
107
  p->pos--;
14884
107
  return TOK_IDENT;
14885
}
14886
14887
28
static int getstr(struct pstate *p) {
14888
28
  int quote = *p->pos++;
14889
28
  p->tok.ptr++;
14890

77
  while (p->pos[0] != '\0' && p->pos[0] != quote) {
14891

30
    if (p->pos[0] == '\\' && p->pos[1] != '\0' &&
14892
18
        (p->pos[1] == quote || strchr("bfnrtv\\", p->pos[1]) != NULL)) {
14893
3
      p->pos += 2;
14894
    } else {
14895
18
      p->pos++;
14896
    }
14897
  }
14898
28
  p->tok.len = p->pos - p->tok.ptr;
14899
28
  return TOK_STR;
14900
}
14901
14902
471
static void skip_spaces_and_comments(struct pstate *p) {
14903
  const char *pos;
14904
  do {
14905
471
    pos = p->pos;
14906
984
    while (mjs_is_space(p->pos[0])) {
14907
42
      if (p->pos[0] == '\n') p->line_no++;
14908
42
      p->pos++;
14909
    }
14910

471
    if (p->pos[0] == '/' && p->pos[1] == '/') {
14911

2
      while (p->pos[0] != '\0' && p->pos[0] != '\n') p->pos++;
14912
    }
14913

471
    if (p->pos[0] == '/' && p->pos[1] == '*') {
14914
4
      p->pos += 2;
14915
10
      while (p->pos[0] != '\0') {
14916
2
        if (p->pos[0] == '\n') p->line_no++;
14917

2
        if (p->pos[0] == '*' && p->pos[1] == '/') {
14918
          p->pos += 2;
14919
          break;
14920
        }
14921
2
        p->pos++;
14922
      }
14923
    }
14924
471
  } while (pos < p->pos);
14925
427
}
14926
14927
427
static int ptranslate(int tok) {
14928
#define DT(a, b) ((a) << 8 | (b))
14929
#define TT(a, b, c) ((a) << 16 | (b) << 8 | (c))
14930
#define QT(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
14931
  /* Map token ID produced by mjs_tok.c to token ID produced by lemon */
14932
  /* clang-format off */
14933












427
  switch (tok) {
14934
2
    case ':': return TOK_COLON;
14935
3
    case ';': return TOK_SEMICOLON;
14936
2
    case ',': return TOK_COMMA;
14937
4
    case '=': return TOK_ASSIGN;
14938
10
    case '{': return TOK_OPEN_CURLY;
14939
8
    case '}': return TOK_CLOSE_CURLY;
14940
8
    case '(': return TOK_OPEN_PAREN;
14941
13
    case ')': return TOK_CLOSE_PAREN;
14942
2
    case '[': return TOK_OPEN_BRACKET;
14943
2
    case ']': return TOK_CLOSE_BRACKET;
14944
6
    case '*': return TOK_MUL;
14945
4
    case '+': return TOK_PLUS;
14946
9
    case '-': return TOK_MINUS;
14947
6
    case '/': return TOK_DIV;
14948
2
    case '%': return TOK_REM;
14949
7
    case '&': return TOK_AND;
14950
9
    case '|': return TOK_OR;
14951
4
    case '^': return TOK_XOR;
14952
2
    case '.': return TOK_DOT;
14953
4
    case '?': return TOK_QUESTION;
14954
2
    case '!': return TOK_NOT;
14955
2
    case '~': return TOK_TILDA;
14956
4
    case '<': return TOK_LT;
14957
2
    case '>': return TOK_GT;
14958
1
    case DT('<','<'): return TOK_LSHIFT;
14959
2
    case DT('>','>'): return TOK_RSHIFT;
14960
5
    case DT('-','-'): return TOK_MINUS_MINUS;
14961
3
    case DT('+','+'): return TOK_PLUS_PLUS;
14962
2
    case DT('+','='): return TOK_PLUS_ASSIGN;
14963
    case DT('-','='): return TOK_MINUS_ASSIGN;
14964
2
    case DT('*','='): return TOK_MUL_ASSIGN;
14965
2
    case DT('/','='): return TOK_DIV_ASSIGN;
14966
2
    case DT('&','='): return TOK_AND_ASSIGN;
14967
    case DT('|','='): return TOK_OR_ASSIGN;
14968
2
    case DT('%','='): return TOK_REM_ASSIGN;
14969
2
    case DT('^','='): return TOK_XOR_ASSIGN;
14970
2
    case DT('=','='): return TOK_EQ;
14971
2
    case DT('!','='): return TOK_NE;
14972
2
    case DT('<','='): return TOK_LE;
14973
2
    case DT('>','='): return TOK_GE;
14974
2
    case DT('&','&'): return TOK_LOGICAL_AND;
14975
    case DT('|','|'): return TOK_LOGICAL_OR;
14976
1
    case TT('=','=','='): return TOK_EQ_EQ;
14977
    case TT('!','=','='): return TOK_NE_NE;
14978
    case TT('<','<','='): return TOK_LSHIFT_ASSIGN;
14979
2
    case TT('>','>','='): return TOK_RSHIFT_ASSIGN;
14980
    case TT('>','>','>'): return TOK_URSHIFT;
14981
    case QT('>','>','>','='): return TOK_URSHIFT_ASSIGN;
14982
  }
14983
  /* clang-format on */
14984
274
  return tok;
14985
}
14986
14987
427
MJS_PRIVATE int pnext(struct pstate *p) {
14988
427
  int tmp, tok = TOK_INVALID;
14989
14990
427
  skip_spaces_and_comments(p);
14991
427
  p->tok.ptr = p->pos;
14992
427
  p->tok.len = 1;
14993
14994
427
  if (p->pos[0] == '\0') {
14995
97
    tok = TOK_EOF;
14996
427
  } if (mjs_is_digit(p->pos[0])) {
14997
42
    tok = getnum(p);
14998

385
  } else if (p->pos[0] == '\'' || p->pos[0] == '"') {
14999
28
    tok = getstr(p);
15000
357
  } else if (mjs_is_ident(p->pos[0])) {
15001
107
    tok = getident(p);
15002
    /*
15003
     * NOTE: getident() has side effects on `p`, and `is_reserved_word_token()`
15004
     * relies on them. Since in C the order of evaluation of the operands is
15005
     * undefined, `is_reserved_word_token()` should be called in a separate
15006
     * statement.
15007
     */
15008
107
    tok += is_reserved_word_token(p->tok.ptr, p->tok.len);
15009
250
  } else if (strchr(",.:;{}[]()?", p->pos[0]) != NULL) {
15010
153
    tok = p->pos[0];
15011

97
  } else if ((tmp = longtok3(p, '<', '<', '=')) != TOK_EOF ||
15012
95
             (tmp = longtok3(p, '>', '>', '=')) != TOK_EOF ||
15013
95
             (tmp = longtok4(p, '>', '>', '>', '=')) != TOK_EOF ||
15014
95
             (tmp = longtok3(p, '>', '>', '>')) != TOK_EOF ||
15015
94
             (tmp = longtok3(p, '=', '=', '=')) != TOK_EOF ||
15016
94
             (tmp = longtok3(p, '!', '=', '=')) != TOK_EOF ||
15017
83
             (tmp = longtok(p, "&", "&=")) != TOK_EOF ||
15018
74
             (tmp = longtok(p, "|", "|=")) != TOK_EOF ||
15019
67
             (tmp = longtok(p, "<", "<=")) != TOK_EOF ||
15020
61
             (tmp = longtok(p, ">", ">=")) != TOK_EOF ||
15021
47
             (tmp = longtok(p, "-", "-=")) != TOK_EOF ||
15022
             (tmp = longtok(p, "+", "+=")) != TOK_EOF) {
15023
59
    tok = tmp;
15024
38
  } else if ((tmp = longtok(p, "^~+-%/*<>=!|&", "=")) != TOK_EOF) {
15025
38
    tok = tmp;
15026
  }
15027
427
  if (p->pos[0] != '\0') p->pos++;
15028
427
  LOG(LL_VERBOSE_DEBUG, ("  --> %d [%.*s]", tok, p->tok.len, p->tok.ptr));
15029
427
  p->prev_tok = p->tok.tok;
15030
427
  p->tok.tok = ptranslate(tok);
15031
427
  return p->tok.tok;
15032
}
15033
#ifdef MJS_MODULE_LINES
15034
#line 1 "mjs/src/mjs_util.c"
15035
#endif
15036
/*
15037
 * Copyright (c) 2017 Cesanta Software Limited
15038
 * All rights reserved
15039
 */
15040
15041
/* Amalgamated: #include "common/cs_varint.h" */
15042
/* Amalgamated: #include "frozen.h" */
15043
/* Amalgamated: #include "mjs/src/mjs_array.h" */
15044
/* Amalgamated: #include "mjs/src/mjs_bcode.h" */
15045
/* Amalgamated: #include "mjs/src/mjs_core.h" */
15046
/* Amalgamated: #include "mjs/src/mjs_internal.h" */
15047
/* Amalgamated: #include "mjs/src/mjs_object.h" */
15048
/* Amalgamated: #include "mjs/src/mjs_primitive.h" */
15049
/* Amalgamated: #include "mjs/src/mjs_string.h" */
15050
/* Amalgamated: #include "mjs/src/mjs_util.h" */
15051
/* Amalgamated: #include "mjs/src/mjs_tok.h" */
15052
15053
1
const char *mjs_typeof(mjs_val_t v) {
15054
1
  return mjs_stringify_type(mjs_get_type(v));
15055
}
15056
15057
1
MJS_PRIVATE const char *mjs_stringify_type(enum mjs_type t) {
15058


1
  switch (t) {
15059
    case MJS_TYPE_NUMBER:
15060
      return "number";
15061
    case MJS_TYPE_BOOLEAN:
15062
      return "boolean";
15063
    case MJS_TYPE_STRING:
15064
1
      return "string";
15065
    case MJS_TYPE_OBJECT_ARRAY:
15066
      return "array";
15067
    case MJS_TYPE_OBJECT_GENERIC:
15068
      return "object";
15069
    case MJS_TYPE_FOREIGN:
15070
      return "foreign_ptr";
15071
    case MJS_TYPE_OBJECT_FUNCTION:
15072
      return "function";
15073
    case MJS_TYPE_NULL:
15074
      return "null";
15075
    case MJS_TYPE_UNDEFINED:
15076
      return "undefined";
15077
    default:
15078
      return "???";
15079
  }
15080
}
15081
15082
66
void mjs_jprintf(mjs_val_t v, struct mjs *mjs, struct json_out *out) {
15083
66
  if (mjs_is_number(v)) {
15084
3
    double iv, d = mjs_get_double(mjs, v);
15085
3
    if (modf(d, &iv) == 0) {
15086
1
      json_printf(out, "%" INT64_FMT, (int64_t) d);
15087
    } else {
15088
2
      json_printf(out, "%f", mjs_get_double(mjs, v));
15089
    }
15090
63
  } else if (mjs_is_boolean(v)) {
15091
2
    json_printf(out, "%s", mjs_get_bool(mjs, v) ? "true" : "false");
15092
61
  } else if (mjs_is_string(v)) {
15093
    size_t i, size;
15094
5
    const char *s = mjs_get_string(mjs, &v, &size);
15095
13
    for (i = 0; i < size; i++) {
15096
8
      int ch = ((unsigned char *) s)[i];
15097
8
      if (isprint(ch)) {
15098
7
        json_printf(out, "%c", ch);
15099
      } else {
15100
1
        json_printf(out, "%s%02x", "\\x", ch);
15101
      }
15102
    }
15103
56
  } else if (mjs_is_array(v)) {
15104
    json_printf(out, "%s", "<array>");
15105
56
  } else if (mjs_is_object(v)) {
15106
    json_printf(out, "%s", "<object>");
15107
56
  } else if (mjs_is_foreign(v)) {
15108
    json_printf(out, "%s%lx%s", "<foreign_ptr@",
15109
                (unsigned long) (uintptr_t) mjs_get_ptr(mjs, v), ">");
15110
56
  } else if (mjs_is_function(v)) {
15111
    json_printf(out, "%s%d%s", "<function@", (int) mjs_get_func_addr(v), ">");
15112
56
  } else if (mjs_is_null(v)) {
15113
1
    json_printf(out, "%s", "null");
15114
55
  } else if (mjs_is_undefined(v)) {
15115
55
    json_printf(out, "%s", "undefined");
15116
  } else {
15117
    json_printf(out, "%s%" INT64_FMT "%s", "<???", (int64_t) v, ">");
15118
  }
15119
66
}
15120
15121
void mjs_sprintf(mjs_val_t v, struct mjs *mjs, char *buf, size_t n) {
15122
  struct json_out out = JSON_OUT_BUF(buf, n);
15123
  mjs_jprintf(v, mjs, &out);
15124
}
15125
15126
66
void mjs_fprintf(mjs_val_t v, struct mjs *mjs, FILE *fp) {
15127
66
  struct json_out out = JSON_OUT_FILE(fp);
15128
66
  mjs_jprintf(v, mjs, &out);
15129
66
}
15130
15131
#if MJS_ENABLE_DEBUG
15132
15133
248
MJS_PRIVATE const char *opcodetostr(uint8_t opcode) {
15134
  static const char *names[] = {
15135
      "NOP", "DROP", "DUP", "SWAP", "JMP", "JMP_TRUE", "JMP_NEUTRAL_TRUE",
15136
      "JMP_FALSE", "JMP_NEUTRAL_FALSE", "FIND_SCOPE", "PUSH_SCOPE", "PUSH_STR",
15137
      "PUSH_TRUE", "PUSH_FALSE", "PUSH_INT", "PUSH_DBL", "PUSH_NULL",
15138
      "PUSH_UNDEF", "PUSH_OBJ", "PUSH_ARRAY", "PUSH_FUNC", "PUSH_THIS", "GET",
15139
      "CREATE", "EXPR", "APPEND", "SET_ARG", "NEW_SCOPE", "DEL_SCOPE", "CALL",
15140
      "RETURN", "LOOP", "BREAK", "CONTINUE", "SETRETVAL", "EXIT", "BCODE_HDR",
15141
      "ARGS", "FOR_IN_NEXT",
15142
  };
15143
248
  const char *name = "???";
15144
  assert(ARRAY_SIZE(names) == OP_MAX);
15145
248
  if (opcode < ARRAY_SIZE(names)) name = names[opcode];
15146
248
  return name;
15147
}
15148
15149
248
MJS_PRIVATE size_t mjs_disasm_single(const uint8_t *code, size_t i) {
15150
  char buf[40];
15151
248
  size_t start_i = i;
15152
  size_t llen;
15153
  uint64_t n;
15154
15155
248
  snprintf(buf, sizeof(buf), "\t%-3u %-8s", (unsigned) i, opcodetostr(code[i]));
15156
15157


248
  switch (code[i]) {
15158
    case OP_PUSH_FUNC: {
15159
      cs_varint_decode(&code[i + 1], ~0, &n, &llen);
15160
      LOG(LL_VERBOSE_DEBUG, ("%s %04u", buf, (unsigned) (i - n)));
15161
      i += llen;
15162
      break;
15163
    }
15164
    case OP_PUSH_INT: {
15165
31
      cs_varint_decode(&code[i + 1], ~0, &n, &llen);
15166
31
      LOG(LL_VERBOSE_DEBUG, ("%s\t%lu", buf, (unsigned long) n));
15167
31
      i += llen;
15168
31
      break;
15169
    }
15170
    case OP_SET_ARG: {
15171
      size_t llen2;
15172
      uint64_t arg_no;
15173
      cs_varint_decode(&code[i + 1], ~0, &arg_no, &llen);
15174
      cs_varint_decode(&code[i + llen + 1], ~0, &n, &llen2);
15175
      LOG(LL_VERBOSE_DEBUG, ("%s\t[%.*s] %u", buf, (int) n,
15176
                             code + i + 1 + llen + llen2, (unsigned) arg_no));
15177
      i += llen + llen2 + n;
15178
      break;
15179
    }
15180
    case OP_PUSH_STR:
15181
    case OP_PUSH_DBL: {
15182
50
      cs_varint_decode(&code[i + 1], ~0, &n, &llen);
15183
50
      LOG(LL_VERBOSE_DEBUG, ("%s\t[%.*s]", buf, (int) n, code + i + 1 + llen));
15184
50
      i += llen + n;
15185
50
      break;
15186
    }
15187
    case OP_JMP:
15188
    case OP_JMP_TRUE:
15189
    case OP_JMP_NEUTRAL_TRUE:
15190
    case OP_JMP_FALSE:
15191
    case OP_JMP_NEUTRAL_FALSE: {
15192
      cs_varint_decode(&code[i + 1], ~0, &n, &llen);
15193
      LOG(LL_VERBOSE_DEBUG,
15194
          ("%s\t%u", buf,
15195
           (unsigned) (i + n + llen +
15196
                       1 /* becaue i will be incremented on the usual terms */)));
15197
      i += llen;
15198
      break;
15199
    }
15200
    case OP_LOOP: {
15201
      size_t l1, l2;
15202
      uint64_t n1, n2;
15203
      cs_varint_decode(&code[i + 1], ~0, &n1, &l1);
15204
      cs_varint_decode(&code[i + l1 + 1], ~0, &n2, &l2);
15205
      LOG(LL_VERBOSE_DEBUG,
15206
          ("%s\tB:%lu C:%lu (%d)", buf,
15207
           (unsigned long) (i + 1 /* OP_LOOP */ + l1 + n1),
15208
           (unsigned long) (i + 1 /* OP_LOOP */ + l1 + l2 + n2), (int) i));
15209
      i += l1 + l2;
15210
      break;
15211
    }
15212
    case OP_EXPR: {
15213
13
      int op = code[i + 1];
15214
13
      const char *name = "???";
15215
      /* clang-format off */
15216











13
      switch (op) {
15217
        case TOK_DOT:       name = "."; break;
15218
        case TOK_MINUS:     name = "-"; break;
15219
        case TOK_PLUS:      name = "+"; break;
15220
        case TOK_MUL:       name = "*"; break;
15221
5
        case TOK_DIV:       name = "/"; break;
15222
        case TOK_REM:       name = "%"; break;
15223
        case TOK_XOR:       name = "^"; break;
15224
        case TOK_AND:       name = "&"; break;
15225
3
        case TOK_OR:        name = "|"; break;
15226
        case TOK_LSHIFT:    name = "<<"; break;
15227
        case TOK_RSHIFT:    name = ">>"; break;
15228
        case TOK_URSHIFT:   name = ">>>"; break;
15229
2
        case TOK_UNARY_MINUS:   name = "- (unary)"; break;
15230
        case TOK_UNARY_PLUS:    name = "+ (unary)"; break;
15231
        case TOK_NOT:       name = "!"; break;
15232
        case TOK_TILDA:     name = "~"; break;
15233
        case TOK_EQ:        name = "=="; break;
15234
        case TOK_NE:        name = "!="; break;
15235
        case TOK_EQ_EQ:     name = "==="; break;
15236
        case TOK_NE_NE:     name = "!=="; break;
15237
        case TOK_LT:        name = "<"; break;
15238
        case TOK_GT:        name = ">"; break;
15239
        case TOK_LE:        name = "<="; break;
15240
        case TOK_GE:        name = ">="; break;
15241
        case TOK_ASSIGN:    name = "="; break;
15242
        case TOK_POSTFIX_PLUS:  name = "++ (postfix)"; break;
15243
        case TOK_POSTFIX_MINUS: name = "-- (postfix)"; break;
15244
2
        case TOK_MINUS_MINUS:   name = "--"; break;
15245
        case TOK_PLUS_PLUS:     name = "++"; break;
15246
        case TOK_LOGICAL_AND:   name = "&&"; break;
15247
        case TOK_LOGICAL_OR:    name = "||"; break;
15248
1
        case TOK_KEYWORD_TYPEOF:  name = "typeof"; break;
15249
        case TOK_PLUS_ASSIGN:     name = "+="; break;
15250
        case TOK_MINUS_ASSIGN:    name = "-="; break;
15251
        case TOK_MUL_ASSIGN:      name = "*="; break;
15252
        case TOK_DIV_ASSIGN:      name = "/="; break;
15253
        case TOK_REM_ASSIGN:      name = "%="; break;
15254
        case TOK_XOR_ASSIGN:      name = "^="; break;
15255
        case TOK_AND_ASSIGN:      name = "&="; break;
15256
        case TOK_OR_ASSIGN:       name = "|="; break;
15257
        case TOK_LSHIFT_ASSIGN:   name = "<<="; break;
15258
        case TOK_RSHIFT_ASSIGN:   name = ">>="; break;
15259
        case TOK_URSHIFT_ASSIGN:  name = ">>>="; break;
15260
      }
15261
      /* clang-format on */
15262
13
      LOG(LL_VERBOSE_DEBUG, ("%s\t%s", buf, name));
15263
13
      i++;
15264
13
      break;
15265
    }
15266
    case OP_BCODE_HEADER: {
15267
66
      size_t start = 0;
15268
66
      mjs_header_item_t map_offset = 0, total_size = 0;
15269
66
      start = i;
15270
66
      memcpy(&total_size, &code[i + 1], sizeof(total_size));
15271
66
      memcpy(&map_offset,
15272
66
             &code[i + 1 + MJS_HDR_ITEM_MAP_OFFSET * sizeof(total_size)],
15273
             sizeof(map_offset));
15274
66
      i += sizeof(mjs_header_item_t) * MJS_HDR_ITEMS_CNT;
15275
66
      LOG(LL_VERBOSE_DEBUG, ("%s\t[%s] end:%lu map_offset: %lu", buf,
15276
                             &code[i + 1], (unsigned long) start + total_size,
15277
                             (unsigned long) start + map_offset));
15278
66
      i += strlen((char *) (code + i + 1)) + 1;
15279
66
      break;
15280
    }
15281
    default:
15282
88
      LOG(LL_VERBOSE_DEBUG, ("%s", buf));
15283
88
      break;
15284
  }
15285
248
  return i - start_i;
15286
}
15287
15288
void mjs_disasm(const uint8_t *code, size_t len) {
15289
  size_t i, start = 0;
15290
  mjs_header_item_t map_offset = 0, total_size = 0;
15291
15292
  for (i = 0; i < len; i++) {
15293
    size_t delta = mjs_disasm_single(code, i);
15294
    if (code[i] == OP_BCODE_HEADER) {
15295
      start = i;
15296
      memcpy(&total_size, &code[i + 1], sizeof(total_size));
15297
      memcpy(&map_offset,
15298
             &code[i + 1 + MJS_HDR_ITEM_MAP_OFFSET * sizeof(total_size)],
15299
             sizeof(map_offset));
15300
    }
15301
15302
    i += delta;
15303
15304
    if (map_offset > 0 && i == start + map_offset) {
15305
      i = start + total_size - 1;
15306
      continue;
15307
    }
15308
  }
15309
}
15310
15311
static void mjs_dump_obj_stack(const char *name, const struct mbuf *m,
15312
                               struct mjs *mjs) {
15313
  char buf[50];
15314
  size_t i, n;
15315
  n = mjs_stack_size(m);
15316
  LOG(LL_VERBOSE_DEBUG, ("%12s (%d elems): ", name, (int) n));
15317
  for (i = 0; i < n; i++) {
15318
    mjs_sprintf(((mjs_val_t *) m->buf)[i], mjs, buf, sizeof(buf));
15319
    LOG(LL_VERBOSE_DEBUG, ("%34s", buf));
15320
  }
15321
}
15322
15323
void mjs_dump(struct mjs *mjs, int do_disasm) {
15324
  LOG(LL_VERBOSE_DEBUG, ("------- MJS VM DUMP BEGIN"));
15325
  mjs_dump_obj_stack("DATA_STACK", &mjs->stack, mjs);
15326
  mjs_dump_obj_stack("CALL_STACK", &mjs->call_stack, mjs);
15327
  mjs_dump_obj_stack("SCOPES", &mjs->scopes, mjs);
15328
  mjs_dump_obj_stack("LOOP_OFFSETS", &mjs->loop_addresses, mjs);
15329
  mjs_dump_obj_stack("ARG_STACK", &mjs->arg_stack, mjs);
15330
  if (do_disasm) {
15331
    int parts_cnt = mjs_bcode_parts_cnt(mjs);
15332
    int i;
15333
    LOG(LL_VERBOSE_DEBUG, ("%23s", "CODE:"));
15334
    for (i = 0; i < parts_cnt; i++) {
15335
      struct mjs_bcode_part *bp = mjs_bcode_part_get(mjs, i);
15336
      mjs_disasm((uint8_t *) bp->data.p, bp->data.len);
15337
    }
15338
  }
15339
  LOG(LL_VERBOSE_DEBUG, ("------- MJS VM DUMP END"));
15340
}
15341
15342
MJS_PRIVATE int mjs_check_arg(struct mjs *mjs, int arg_num,
15343
                              const char *arg_name, enum mjs_type expected_type,
15344
                              mjs_val_t *parg) {
15345
  mjs_val_t arg = MJS_UNDEFINED;
15346
  enum mjs_type actual_type;
15347
15348
  if (arg_num >= 0) {
15349
    int nargs = mjs_nargs(mjs);
15350
    if (nargs < arg_num + 1) {
15351
      mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "missing argument %s", arg_name);
15352
      return 0;
15353
    }
15354
15355
    arg = mjs_arg(mjs, arg_num);
15356
  } else {
15357
    /* use `this` */
15358
    arg = mjs->vals.this_obj;
15359
  }
15360
15361
  actual_type = mjs_get_type(arg);
15362
  if (actual_type != expected_type) {
15363
    mjs_prepend_errorf(mjs, MJS_TYPE_ERROR, "%s should be a %s, %s given",
15364
                       arg_name, mjs_stringify_type(expected_type),
15365
                       mjs_stringify_type(actual_type));
15366
    return 0;
15367
  }
15368
15369
  if (parg != NULL) {
15370
    *parg = arg;
15371
  }
15372
15373
  return 1;
15374
}
15375
15376
MJS_PRIVATE int mjs_normalize_idx(int idx, int size) {
15377
  if (idx < 0) {
15378
    idx = size + idx;
15379
    if (idx < 0) {
15380
      idx = 0;
15381
    }
15382
  }
15383
  if (idx > size) {
15384
    idx = size;
15385
  }
15386
  return idx;
15387
}
15388
15389
50
MJS_PRIVATE const char *mjs_get_bcode_filename(struct mjs *mjs,
15390
                                               struct mjs_bcode_part *bp) {
15391
  (void) mjs;
15392
50
  return bp->data.p + 1 /* OP_BCODE_HEADER */ +
15393
         sizeof(mjs_header_item_t) * MJS_HDR_ITEMS_CNT;
15394
}
15395
15396
50
const char *mjs_get_bcode_filename_by_offset(struct mjs *mjs, int offset) {
15397
50
  const char *ret = NULL;
15398
50
  struct mjs_bcode_part *bp = mjs_bcode_part_get_by_offset(mjs, offset);
15399
50
  if (bp != NULL) {
15400
50
    ret = mjs_get_bcode_filename(mjs, bp);
15401
  }
15402
50
  return ret;
15403
}
15404
15405
50
int mjs_get_lineno_by_offset(struct mjs *mjs, int offset) {
15406
  size_t llen;
15407
  uint64_t map_len;
15408
50
  int prev_line_no, ret = 1;
15409
50
  struct mjs_bcode_part *bp = mjs_bcode_part_get_by_offset(mjs, offset);
15410
  uint8_t *p, *pe;
15411
50
  if (bp != NULL) {
15412
    mjs_header_item_t map_offset, bcode_offset;
15413
50
    memcpy(&map_offset, bp->data.p + 1 /* OP_BCODE_HEADER */ +
15414
                            sizeof(mjs_header_item_t) * MJS_HDR_ITEM_MAP_OFFSET,
15415
           sizeof(map_offset));
15416
15417
50
    memcpy(&bcode_offset,
15418
50
           bp->data.p + 1 /* OP_BCODE_HEADER */ +
15419
               sizeof(mjs_header_item_t) * MJS_HDR_ITEM_BCODE_OFFSET,
15420
           sizeof(bcode_offset));
15421
15422
50
    offset -= (1 /* OP_BCODE_HEADER */ + bcode_offset) + bp->start_idx;
15423
15424
    /* get pointer to the length of the map followed by the map itself */
15425
50
    p = (uint8_t *) bp->data.p + 1 /* OP_BCODE_HEADER */ + map_offset;
15426
15427
50
    cs_varint_decode(p, ~0, &map_len, &llen);
15428
50
    p += llen;
15429
50
    pe = p + map_len;
15430
15431
50
    prev_line_no = 1;
15432
101
    while (p < pe) {
15433
      uint64_t cur_offset, line_no;
15434
6
      cs_varint_decode(p, ~0, &cur_offset, &llen);
15435
6
      p += llen;
15436
6
      cs_varint_decode(p, ~0, &line_no, &llen);
15437
6
      p += llen;
15438
15439
6
      if (cur_offset >= (uint64_t) offset) {
15440
5
        ret = prev_line_no;
15441
5
        break;
15442
      }
15443
1
      prev_line_no = line_no;
15444
    }
15445
  }
15446
50
  return ret;
15447
}
15448
15449
int mjs_get_offset_by_call_frame_num(struct mjs *mjs, int cf_num) {
15450
  int ret = -1;
15451
  if (cf_num == 0) {
15452
    /* Return current bcode offset */
15453
    ret = mjs->cur_bcode_offset;
15454
  } else if (cf_num > 0 &&
15455
             mjs->call_stack.len >=
15456
                 sizeof(mjs_val_t) * CALL_STACK_FRAME_ITEMS_CNT * cf_num) {
15457
    /* Get offset from the call_stack */
15458
    int pos = CALL_STACK_FRAME_ITEM_RETURN_ADDR +
15459
              CALL_STACK_FRAME_ITEMS_CNT * (cf_num - 1);
15460
    mjs_val_t val = *vptr(&mjs->call_stack, -1 - pos);
15461
    ret = mjs_get_int(mjs, val);
15462
  }
15463
  return ret;
15464
}
15465
15466
#endif
15467
#endif /* MJS_EXPORT_INTERNAL_HEADERS */